From a425379c4c633f159c9f7d5f6da94cfa79ad3cc3 Mon Sep 17 00:00:00 2001 From: Leticia Choo Date: Thu, 13 Jul 2017 18:37:47 +0800 Subject: [PATCH 1/6] ESS-911 Fixes for setting "sprop-stereo" for opus param option. --- doc/classes/Skylink.html | 74 ++++++++++++------------ doc/data.json | 82 +++++++++++++-------------- doc/files/source_stream-media.js.html | 14 +++-- doc/files/source_stream-sdp.js.html | 5 ++ publish/skylink.complete.js | 23 +++++--- publish/skylink.complete.min.js | 6 +- publish/skylink.debug.js | 21 ++++--- publish/skylink.min.js | 6 +- source/stream-media.js | 14 +++-- source/stream-sdp.js | 5 ++ 10 files changed, 140 insertions(+), 110 deletions(-) diff --git a/doc/classes/Skylink.html b/doc/classes/Skylink.html index 9de43edf9..c150be8f2 100644 --- a/doc/classes/Skylink.html +++ b/doc/classes/Skylink.html @@ -3854,7 +3854,7 @@

_addLocalMediaStreams

-   Defined in: source/stream-media.js:2085 +   Defined in: source/stream-media.js:2087 @@ -4026,7 +4026,7 @@

_addSDPMediaStreamTrackIDs

-   Defined in: source/stream-sdp.js:406 +   Defined in: source/stream-sdp.js:411 @@ -6088,7 +6088,7 @@

_getCodecsSupport

-   Defined in: source/stream-sdp.js:796 +   Defined in: source/stream-sdp.js:801 @@ -6357,7 +6357,7 @@

_getSDPEdgeVideoSupports

-   Defined in: source/stream-sdp.js:1136 +   Defined in: source/stream-sdp.js:1141 @@ -6442,7 +6442,7 @@

_getSDPFingerprint

-   Defined in: source/stream-sdp.js:1098 +   Defined in: source/stream-sdp.js:1103 @@ -6527,7 +6527,7 @@

_getSDPSelectedCodec

-   Defined in: source/stream-sdp.js:697 +   Defined in: source/stream-sdp.js:702 @@ -7039,7 +7039,7 @@

_handleEndedStreams

-   Defined in: source/stream-media.js:2183 +   Defined in: source/stream-media.js:2185 @@ -7124,7 +7124,7 @@

_handleSDPConnectionSettings

-   Defined in: source/stream-sdp.js:889 +   Defined in: source/stream-sdp.js:894 @@ -7898,7 +7898,7 @@

_muteStreams

-   Defined in: source/stream-media.js:1581 +   Defined in: source/stream-media.js:1583 @@ -8242,7 +8242,7 @@

_onRemoteStreamAdded

-   Defined in: source/stream-media.js:2051 +   Defined in: source/stream-media.js:2053 @@ -8327,7 +8327,7 @@

_onStreamAccessError

-   Defined in: source/stream-media.js:2011 +   Defined in: source/stream-media.js:2013 @@ -8412,7 +8412,7 @@

_onStreamAccessSuccess

-   Defined in: source/stream-media.js:1865 +   Defined in: source/stream-media.js:1867 @@ -8753,7 +8753,7 @@

_parseStreamSettings

-   Defined in: source/stream-media.js:1712 +   Defined in: source/stream-media.js:1714 @@ -9787,7 +9787,7 @@

_removeSDPCodecs

-   Defined in: source/stream-sdp.js:607 +   Defined in: source/stream-sdp.js:612 @@ -9872,7 +9872,7 @@

_removeSDPFilteredCandidates

-   Defined in: source/stream-sdp.js:754 +   Defined in: source/stream-sdp.js:759 @@ -9957,7 +9957,7 @@

_removeSDPFirefoxH264Pref

-   Defined in: source/stream-sdp.js:390 +   Defined in: source/stream-sdp.js:395 @@ -10044,7 +10044,7 @@

_removeSDPREMBPackets

-   Defined in: source/stream-sdp.js:681 +   Defined in: source/stream-sdp.js:686 @@ -10129,7 +10129,7 @@

_removeSDPUnknownAptRtx

-   Defined in: source/stream-sdp.js:552 +   Defined in: source/stream-sdp.js:557 @@ -11076,7 +11076,7 @@

_setSDPBitrate

-   Defined in: source/stream-sdp.js:157 +   Defined in: source/stream-sdp.js:162 @@ -11162,7 +11162,7 @@

_setSDPCodec

-   Defined in: source/stream-sdp.js:293 +   Defined in: source/stream-sdp.js:298 @@ -11603,7 +11603,7 @@

_stopStreams

-   Defined in: source/stream-media.js:1639 +   Defined in: source/stream-media.js:1641 @@ -12721,7 +12721,7 @@

disableAudio

-   Defined in: source/stream-media.js:1077 +   Defined in: source/stream-media.js:1078 @@ -12826,7 +12826,7 @@

disableVideo

-   Defined in: source/stream-media.js:1131 +   Defined in: source/stream-media.js:1132 @@ -12931,7 +12931,7 @@

enableAudio

-   Defined in: source/stream-media.js:1050 +   Defined in: source/stream-media.js:1051 @@ -13036,7 +13036,7 @@

enableVideo

-   Defined in: source/stream-media.js:1104 +   Defined in: source/stream-media.js:1105 @@ -15236,10 +15236,11 @@

Parameters:

DEFAULT: false
Deprecation Warning! - This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo + This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo and + the options.codecParams.audio.opus["sprop-stereo"] parameter in the init() method instead. If the - options.codecParams.audio.opus.stereo is configured, this overrides the - options.audio.stereo setting.
+ options.codecParams.audio.opus.stereo or options.codecParams.audio.opus["sprop-stereo"] + is configured, this overrides the options.audio.stereo setting. The flag if OPUS audio codec stereo band should be configured for sending encoded audio data. When not provided, the default browser configuration is used.
@@ -19150,7 +19151,7 @@

muteStream

-   Defined in: source/stream-media.js:912 +   Defined in: source/stream-media.js:913 @@ -21368,7 +21369,7 @@

sendStream

-   Defined in: source/stream-media.js:650 +   Defined in: source/stream-media.js:651 @@ -22551,7 +22552,7 @@

shareScreen

-   Defined in: source/stream-media.js:1158 +   Defined in: source/stream-media.js:1159 @@ -22699,10 +22700,11 @@

Parameters:

DEFAULT: false

Deprecation Warning! - This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo + This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo and + the options.codecParams.audio.opus["sprop-stereo"] parameter in the init() method instead. If the - options.codecParams.audio.opus.stereo is configured, this overrides the - options.audio.stereo setting.
+ options.codecParams.audio.opus.stereo or options.codecParams.audio.opus["sprop-stereo"] + is configured, this overrides the options.audio.stereo setting. The flag if OPUS audio codec stereo band should be configured for sending encoded audio data. When not provided, the default browser configuration is used.

@@ -23657,7 +23659,7 @@

stopScreen

-   Defined in: source/stream-media.js:1522 +   Defined in: source/stream-media.js:1524 @@ -23780,7 +23782,7 @@

stopStream

-   Defined in: source/stream-media.js:873 +   Defined in: source/stream-media.js:874 diff --git a/doc/data.json b/doc/data.json index 1b7c3249e..d80ccd5da 100644 --- a/doc/data.json +++ b/doc/data.json @@ -9472,7 +9472,7 @@ "props": [ { "name": "stereo", - "description": "
Deprecation Warning!\n This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo\n parameter in the init() method instead. If the\n options.codecParams.audio.opus.stereo is configured, this overrides the\n options.audio.stereo setting.
\n The flag if OPUS audio codec stereo band should be configured for sending encoded audio data.\n When not provided, the default browser configuration is used.", + "description": "
Deprecation Warning!\n This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo and\n the options.codecParams.audio.opus[\"sprop-stereo\"]\n parameter in the init() method instead. If the\n options.codecParams.audio.opus.stereo or options.codecParams.audio.opus[\"sprop-stereo\"]\n is configured, this overrides the options.audio.stereo setting.
\n The flag if OPUS audio codec stereo band should be configured for sending encoded audio data.\n When not provided, the default browser configuration is used.", "type": "Boolean", "optional": true, "optdefault": "false" @@ -9611,7 +9611,7 @@ }, { "file": "source/stream-media.js", - "line": 650, + "line": 651, "description": "
\n Note that if shareScreen() Stream is available despite having\n getUserMedia() Stream available, the\n shareScreen() Stream is sent instead of the\n getUserMedia() Stream to Peers.\n
\nFunction that sends a new getUserMedia() Stream\nto all connected Peers in the Room.", "itemtype": "method", "name": "sendStream", @@ -9649,7 +9649,7 @@ }, { "file": "source/stream-media.js", - "line": 873, + "line": 874, "description": "
\n Note that broadcasted events from muteStream() method,\n stopStream() method,\n stopScreen() method,\n sendMessage() method,\n unlockRoom() method and\n lockRoom() method may be queued when\n sent within less than an interval.\n
\nFunction that stops getUserMedia() Stream.", "itemtype": "method", "name": "stopStream", @@ -9662,7 +9662,7 @@ }, { "file": "source/stream-media.js", - "line": 912, + "line": 913, "description": "
\n Note that broadcasted events from muteStream() method,\n stopStream() method,\n stopScreen() method,\n sendMessage() method,\n unlockRoom() method and\n lockRoom() method may be queued when\n sent within less than an interval.\n
\nFunction that mutes both getUserMedia() Stream and\nshareScreen() Stream audio or video tracks.", "itemtype": "method", "name": "muteStream", @@ -9698,7 +9698,7 @@ }, { "file": "source/stream-media.js", - "line": 1050, + "line": 1051, "description": "
Deprecation Warning!\n This method has been deprecated. Use muteStream() method instead.\n
\nFunction that unmutes both getUserMedia() Stream and\nshareScreen() Stream audio tracks.", "itemtype": "method", "name": "enableAudio", @@ -9713,7 +9713,7 @@ }, { "file": "source/stream-media.js", - "line": 1077, + "line": 1078, "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", @@ -9728,7 +9728,7 @@ }, { "file": "source/stream-media.js", - "line": 1104, + "line": 1105, "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", @@ -9743,7 +9743,7 @@ }, { "file": "source/stream-media.js", - "line": 1131, + "line": 1132, "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", @@ -9758,7 +9758,7 @@ }, { "file": "source/stream-media.js", - "line": 1158, + "line": 1159, "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
\nFunction that retrieves screensharing Stream.", "itemtype": "method", "name": "shareScreen", @@ -9772,7 +9772,7 @@ "props": [ { "name": "stereo", - "description": "
Deprecation Warning!\n This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo\n parameter in the init() method instead. If the\n options.codecParams.audio.opus.stereo is configured, this overrides the\n options.audio.stereo setting.
\n The flag if OPUS audio codec stereo band should be configured for sending encoded audio data.\n When not provided, the default browser configuration is used.", + "description": "
Deprecation Warning!\n This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo and\n the options.codecParams.audio.opus[\"sprop-stereo\"]\n parameter in the init() method instead. If the\n options.codecParams.audio.opus.stereo or options.codecParams.audio.opus[\"sprop-stereo\"]\n is configured, this overrides the options.audio.stereo setting.
\n The flag if OPUS audio codec stereo band should be configured for sending encoded audio data.\n When not provided, the default browser configuration is used.", "type": "Boolean", "optional": true, "optdefault": "false" @@ -9839,7 +9839,7 @@ }, { "file": "source/stream-media.js", - "line": 1522, + "line": 1524, "description": "
\n Note that broadcasted events from muteStream() method,\n stopStream() method,\n stopScreen() method,\n sendMessage() method,\n unlockRoom() method and\n lockRoom() method may be queued when\n sent within less than an interval.\n
\nFunction that stops shareScreen() Stream.", "itemtype": "method", "name": "stopScreen", @@ -9852,7 +9852,7 @@ }, { "file": "source/stream-media.js", - "line": 1581, + "line": 1583, "description": "Function that handles the muting of Stream audio and video tracks.", "itemtype": "method", "name": "_muteStreams", @@ -9863,7 +9863,7 @@ }, { "file": "source/stream-media.js", - "line": 1639, + "line": 1641, "description": "Function that handles stopping the Stream streaming.", "itemtype": "method", "name": "_stopStreams", @@ -9874,7 +9874,7 @@ }, { "file": "source/stream-media.js", - "line": 1712, + "line": 1714, "description": "Function that parses the getUserMedia() settings provided.", "itemtype": "method", "name": "_parseStreamSettings", @@ -9885,7 +9885,7 @@ }, { "file": "source/stream-media.js", - "line": 1865, + "line": 1867, "description": "Function that handles the native navigator.getUserMedia() API success callback result.", "itemtype": "method", "name": "_onStreamAccessSuccess", @@ -9896,7 +9896,7 @@ }, { "file": "source/stream-media.js", - "line": 2011, + "line": 2013, "description": "Function that handles the native navigator.getUserMedia() API failure callback result.", "itemtype": "method", "name": "_onStreamAccessError", @@ -9907,7 +9907,7 @@ }, { "file": "source/stream-media.js", - "line": 2051, + "line": 2053, "description": "Function that handles the RTCPeerConnection.onaddstream remote MediaStream received.", "itemtype": "method", "name": "_onRemoteStreamAdded", @@ -9918,7 +9918,7 @@ }, { "file": "source/stream-media.js", - "line": 2085, + "line": 2087, "description": "Function that sets User's Stream to send to Peer connection.\nPriority for shareScreen() Stream over getUserMedia() Stream.", "itemtype": "method", "name": "_addLocalMediaStreams", @@ -9929,7 +9929,7 @@ }, { "file": "source/stream-media.js", - "line": 2183, + "line": 2185, "description": "Function that handles ended streams.", "itemtype": "method", "name": "_handleEndedStreams", @@ -9951,7 +9951,7 @@ }, { "file": "source/stream-sdp.js", - "line": 157, + "line": 162, "description": "Function that modifies the session description to limit the maximum sending bandwidth.\nSetting this may not necessarily work in Firefox.", "itemtype": "method", "name": "_setSDPBitrate", @@ -9962,7 +9962,7 @@ }, { "file": "source/stream-sdp.js", - "line": 293, + "line": 298, "description": "Function that modifies the session description to set the preferred audio/video codec.", "itemtype": "method", "name": "_setSDPCodec", @@ -9973,7 +9973,7 @@ }, { "file": "source/stream-sdp.js", - "line": 390, + "line": 395, "description": "Function that modifies the session description to remove the previous experimental H264\ncodec that is apparently breaking connections.\nNOTE: We should perhaps not remove it since H264 is supported?", "itemtype": "method", "name": "_removeSDPFirefoxH264Pref", @@ -9984,7 +9984,7 @@ }, { "file": "source/stream-sdp.js", - "line": 406, + "line": 411, "description": "Function that modifies the session description to append the MediaStream and MediaStreamTrack IDs that seems\nto be missing from Firefox answer session description to Chrome connection causing freezes in re-negotiation.", "itemtype": "method", "name": "_addSDPMediaStreamTrackIDs", @@ -9995,7 +9995,7 @@ }, { "file": "source/stream-sdp.js", - "line": 552, + "line": 557, "description": "Function that modifies the session description to remove apt/rtx lines that does exists.", "itemtype": "method", "name": "_removeSDPUnknownAptRtx", @@ -10006,7 +10006,7 @@ }, { "file": "source/stream-sdp.js", - "line": 607, + "line": 612, "description": "Function that modifies the session description to remove codecs.", "itemtype": "method", "name": "_removeSDPCodecs", @@ -10017,7 +10017,7 @@ }, { "file": "source/stream-sdp.js", - "line": 681, + "line": 686, "description": "Function that modifies the session description to remove REMB packets fb.", "itemtype": "method", "name": "_removeSDPREMBPackets", @@ -10028,7 +10028,7 @@ }, { "file": "source/stream-sdp.js", - "line": 697, + "line": 702, "description": "Function that retrieves the session description selected codec.", "itemtype": "method", "name": "_getSDPSelectedCodec", @@ -10039,7 +10039,7 @@ }, { "file": "source/stream-sdp.js", - "line": 754, + "line": 759, "description": "Function that modifies the session description to remove non-relay ICE candidates.", "itemtype": "method", "name": "_removeSDPFilteredCandidates", @@ -10050,7 +10050,7 @@ }, { "file": "source/stream-sdp.js", - "line": 796, + "line": 801, "description": "Function that retrieves the current list of support codecs.", "itemtype": "method", "name": "_getCodecsSupport", @@ -10061,7 +10061,7 @@ }, { "file": "source/stream-sdp.js", - "line": 889, + "line": 894, "description": "Function that modifies the session description to handle the connection settings.\nThis is experimental and never recommended to end-users.", "itemtype": "method", "name": "_handleSDPConnectionSettings", @@ -10072,7 +10072,7 @@ }, { "file": "source/stream-sdp.js", - "line": 1098, + "line": 1103, "description": "Function that parses and retrieves the session description fingerprint.", "itemtype": "method", "name": "_getSDPFingerprint", @@ -10083,7 +10083,7 @@ }, { "file": "source/stream-sdp.js", - "line": 1136, + "line": 1141, "description": "Function that gets edge browser video supports.", "itemtype": "method", "name": "_getSDPEdgeVideoSupports", @@ -10252,39 +10252,39 @@ }, { "message": "unknown tag: trigger", - "line": " source/stream-media.js:650" + "line": " source/stream-media.js:651" }, { "message": "unknown tag: trigger", - "line": " source/stream-media.js:873" + "line": " source/stream-media.js:874" }, { "message": "unknown tag: trigger", - "line": " source/stream-media.js:912" + "line": " source/stream-media.js:913" }, { "message": "unknown tag: trigger", - "line": " source/stream-media.js:1050" + "line": " source/stream-media.js:1051" }, { "message": "unknown tag: trigger", - "line": " source/stream-media.js:1077" + "line": " source/stream-media.js:1078" }, { "message": "unknown tag: trigger", - "line": " source/stream-media.js:1104" + "line": " source/stream-media.js:1105" }, { "message": "unknown tag: trigger", - "line": " source/stream-media.js:1131" + "line": " source/stream-media.js:1132" }, { "message": "unknown tag: trigger", - "line": " source/stream-media.js:1158" + "line": " source/stream-media.js:1159" }, { "message": "unknown tag: trigger", - "line": " source/stream-media.js:1522" + "line": " source/stream-media.js:1524" }, { "message": "Missing item type\nGlobal function that clones an object.", diff --git a/doc/files/source_stream-media.js.html b/doc/files/source_stream-media.js.html index 19818412e..8dffac117 100644 --- a/doc/files/source_stream-media.js.html +++ b/doc/files/source_stream-media.js.html @@ -389,10 +389,11 @@

File: source/stream-media.js

* <code>options.audio.deviceId</code>, <code>options.audio.echoCancellation</code>.</blockquote> * The audio configuration options. * @param {Boolean} [options.audio.stereo=false] <blockquote class="info"><b>Deprecation Warning!</b> - * This property has been deprecated. Configure this with the <code>options.codecParams.audio.opus.stereo</code> + * This property has been deprecated. Configure this with the <code>options.codecParams.audio.opus.stereo</code> and + * the <code>options.codecParams.audio.opus["sprop-stereo"]</code> * parameter in the <a href="#method_init"><code>init()</code> method</a> instead. If the - * <code>options.codecParams.audio.opus.stereo</code> is configured, this overrides the - * <code>options.audio.stereo</code> setting.</blockquote> + * <code>options.codecParams.audio.opus.stereo</code> or <code>options.codecParams.audio.opus["sprop-stereo"]</code> + * is configured, this overrides the <code>options.audio.stereo</code> setting.</blockquote> * The flag if OPUS audio codec stereo band should be configured for sending encoded audio data. * <small>When not provided, the default browser configuration is used.</small> * @param {Boolean} [options.audio.usedtx] <blockquote class="info"><b>Deprecation Warning!</b> @@ -1258,10 +1259,11 @@

File: source/stream-media.js

* @method shareScreen * @param {JSON|Boolean} [enableAudio=false] The flag if audio tracks should be retrieved. * @param {Boolean} [enableAudio.stereo=false] <blockquote class="info"><b>Deprecation Warning!</b> - * This property has been deprecated. Configure this with the <code>options.codecParams.audio.opus.stereo</code> + * This property has been deprecated. Configure this with the <code>options.codecParams.audio.opus.stereo</code> and + * the <code>options.codecParams.audio.opus["sprop-stereo"]</code> * parameter in the <a href="#method_init"><code>init()</code> method</a> instead. If the - * <code>options.codecParams.audio.opus.stereo</code> is configured, this overrides the - * <code>options.audio.stereo</code> setting.</blockquote> + * <code>options.codecParams.audio.opus.stereo</code> or <code>options.codecParams.audio.opus["sprop-stereo"]</code> + * is configured, this overrides the <code>options.audio.stereo</code> setting.</blockquote> * The flag if OPUS audio codec stereo band should be configured for sending encoded audio data. * <small>When not provided, the default browser configuration is used.</small> * @param {Boolean} [enableAudio.usedtx] <blockquote class="info"><b>Deprecation Warning!</b> diff --git a/doc/files/source_stream-sdp.js.html b/doc/files/source_stream-sdp.js.html index a3d5ad806..eb0412ffc 100644 --- a/doc/files/source_stream-sdp.js.html +++ b/doc/files/source_stream-sdp.js.html @@ -162,6 +162,11 @@

File: source/stream-sdp.js

} else if (typeof audioSettings.stereo === 'boolean') { opusOptions.stereo = audioSettings.stereo; } + if (typeof self._codecParams.audio.opus['sprop-stereo'] === 'boolean') { + opusOptions['sprop-stereo'] = self._codecParams.audio.opus['sprop-stereo']; + } else if (typeof audioSettings.stereo === 'boolean') { + opusOptions['sprop-stereo'] = audioSettings.stereo; + } if (typeof self._codecParams.audio.opus.usedtx === 'boolean') { opusOptions.usedtx = self._codecParams.audio.opus.usedtx; } else if (typeof audioSettings.usedtx === 'boolean') { diff --git a/publish/skylink.complete.js b/publish/skylink.complete.js index a7b8ecbc4..638985175 100644 --- a/publish/skylink.complete.js +++ b/publish/skylink.complete.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.23 - Thu Jun 15 2017 13:32:44 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.23 - Thu Jul 13 2017 18:37:09 GMT+0800 (SGT) */ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.io = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;ooptions.audio.deviceId, options.audio.echoCancellation. * The audio configuration options. * @param {Boolean} [options.audio.stereo=false]
Deprecation Warning! - * This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo + * This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo and + * the options.codecParams.audio.opus["sprop-stereo"] * parameter in the init() method instead. If the - * options.codecParams.audio.opus.stereo is configured, this overrides the - * options.audio.stereo setting.
+ * options.codecParams.audio.opus.stereo or options.codecParams.audio.opus["sprop-stereo"] + * is configured, this overrides the options.audio.stereo setting. * The flag if OPUS audio codec stereo band should be configured for sending encoded audio data. * When not provided, the default browser configuration is used. * @param {Boolean} [options.audio.usedtx]
Deprecation Warning! @@ -28572,10 +28573,11 @@ Skylink.prototype.disableVideo = function() { * @method shareScreen * @param {JSON|Boolean} [enableAudio=false] The flag if audio tracks should be retrieved. * @param {Boolean} [enableAudio.stereo=false]
Deprecation Warning! - * This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo + * This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo and + * the options.codecParams.audio.opus["sprop-stereo"] * parameter in the init() method instead. If the - * options.codecParams.audio.opus.stereo is configured, this overrides the - * options.audio.stereo setting.
+ * options.codecParams.audio.opus.stereo or options.codecParams.audio.opus["sprop-stereo"] + * is configured, this overrides the options.audio.stereo setting.
* The flag if OPUS audio codec stereo band should be configured for sending encoded audio data. * When not provided, the default browser configuration is used. * @param {Boolean} [enableAudio.usedtx]
Deprecation Warning! @@ -29698,6 +29700,11 @@ Skylink.prototype._setSDPCodecParams = function(targetMid, sessionDescription) { } else if (typeof audioSettings.stereo === 'boolean') { opusOptions.stereo = audioSettings.stereo; } + if (typeof self._codecParams.audio.opus['sprop-stereo'] === 'boolean') { + opusOptions['sprop-stereo'] = self._codecParams.audio.opus['sprop-stereo']; + } else if (typeof audioSettings.stereo === 'boolean') { + opusOptions['sprop-stereo'] = audioSettings.stereo; + } if (typeof self._codecParams.audio.opus.usedtx === 'boolean') { opusOptions.usedtx = self._codecParams.audio.opus.usedtx; } else if (typeof audioSettings.usedtx === 'boolean') { diff --git a/publish/skylink.complete.min.js b/publish/skylink.complete.min.js index 9deb947f0..35f1aed47 100644 --- a/publish/skylink.complete.min.js +++ b/publish/skylink.complete.min.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.23 - 2017-06-15 */ +/*! skylinkjs - v0.6.23 - 2017-07-13 */ !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;i=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"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,self._useEdgeWebRTC=useEdgeWebRTC,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}),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})):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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"Network error occurred. (Status: "+xhr.status+")",errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom)},xhr.onprogress=function(){log.debug([null,"XMLHttpRequest",method,"Retrieving information and config from webserver. Url:"],url),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},Skylink.prototype._parseInfo=function(info){if(log.log("Parsing parameter from server",info),!info.pc_constraints&&!info.offer_constraints)return void this._trigger("readyStateChange",this.READY_STATE_CHANGE.ERROR,{status:200,content:info.info,errorCode:info.error},self._selectedRoom);log.debug("Peer connection constraints:",info.pc_constraints),log.debug("Offer constraints:",info.offer_constraints),this._key=info.cid,this._appKeyOwner=info.apiOwner,this._signalingServer=info.ipSigserver,this._isPrivileged=info.isPrivileged,this._autoIntroduce=info.autoIntroduce,this._user={uid:info.username,token:info.userCred,timeStamp:info.timeStamp,streams:[],info:{}},this._room={id:info.room_key,token:info.roomCred,startDateTime:info.start,duration:info.len,connection:{peerConstraints:JSON.parse(info.pc_constraints),peerConfig:null,offerConstraints:JSON.parse(info.offer_constraints),sdpConstraints:{mandatory:{OfferToReceiveAudio:!0,OfferToReceiveVideo:!0}},mediaConstraints:JSON.parse(info.media_constraints)}},this._socketPorts={"http:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,this._trigger("readyStateChange",this.READY_STATE_CHANGE.COMPLETED,null,this._selectedRoom),log.info("Parsed parameters from webserver. Ready for web-realtime communication")},Skylink.prototype._loadInfo=function(){var self=this,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!function(){try{var p=new window.RTCPeerConnection(null);return["object","function"].indexOf(typeof p.createOffer)>-1&&null!==p.createOffer}catch(e){return!1}}())return window.RTCPeerConnection&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);self._getCodecsSupport(function(error){return error?(log.error(error),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:error.message||error.toString(),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):0===Object.keys(self._currentCodecSupport.audio).length&&0===Object.keys(self._currentCodecSupport.video).length?(log.error("No audio/video codecs available to start connection."),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No API Path is found",errorCode:self.READY_STATE_CHANGE_ERROR.NO_PATH},self._selectedRoom)):(log.error("XMLHttpRequest not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"XMLHttpRequest not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_XMLHTTPREQUEST_SUPPORT},self._selectedRoom)):(log.error("Socket.io not loaded. Please load socket.io"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"Socket.io not found",errorCode:self.READY_STATE_CHANGE_ERROR.NO_SOCKET_IO},self._selectedRoom))},Skylink.prototype._initSelectedRoom=function(room,callback){var self=this;if("function"==typeof room||void 0===room)return void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null,useEdgeWebRTC:self._useEdgeWebRTC};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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,target:message.target,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._redirectHandler=function(message){if(log.log(["Server",null,message.type,"System action warning:"],{message:message.info,reason:message.reason,action:message.action}),message.action===this.SYSTEM_ACTION.REJECT)for(var key in this._peerConnections)this._peerConnections.hasOwnProperty(key)&&this._removePeer(key);"toClose"===message.reason&&(message.reason="toclose"),this._trigger("systemAction",message.action,message.info,message.reason)},Skylink.prototype._updateUserEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer updated userData:"],message.userData),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].userData=message.stamp}this._peerInformations[targetMid].userData=message.userData||{},this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._roomLockEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,message.type,"Room lock status:"],message.lock),this._trigger("roomLock",message.lock,targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._muteAudioEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's audio muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].audioMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.audioMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,message.type,"Peer does not have any user information"])},Skylink.prototype._muteVideoEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's video muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].videoMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.videoMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._streamEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Peer's stream status:"],message.status),this._peerInformations[targetMid]&&message.streamId?(this._streamsSession[targetMid]=this._streamsSession[targetMid]||{},"ended"===message.status&&(message.settings&&"object"==typeof message.settings&&void 0===this._streamsSession[targetMid][message.streamId]&&(this._streamsSession[targetMid][message.streamId]={audio:message.settings.audio,video:message.settings.video}),this._handleEndedStreams(targetMid,message.streamId))):log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._byeHandler=function(message){var targetMid=message.mid;(this._user||{}).sid!==targetMid?(log.log([targetMid,null,message.type,"Peer has left the room"]),this._removePeer(targetMid)):log.log([targetMid,null,message.type,"Self has left the room"])},Skylink.prototype._privateMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received private message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!0,targetPeerId:message.target,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._publicMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received public message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!1,targetPeerId:null,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._recordingEventHandler=function(message){var self=this;if(log.debug(["MCU","Recording",null,"Received recording message ->"],message),"on"===message.action)self._recordings[message.recordingId]||(log.debug(["MCU","Recording",message.recordingId,"Started recording"]),self._currentRecordingId=message.recordingId,self._recordings[message.recordingId]={active:!0,state:self.RECORDING_STATE.START,startedDateTime:(new Date).toISOString(),endedDateTime:null,mixingDateTime:null,links:null,error:null},self._recordingStartInterval=setTimeout(function(){log.log(["MCU","Recording",message.recordingId,"4 seconds has been recorded. Recording can be stopped now"]),self._recordingStartInterval=null},4e3),self._trigger("recordingState",self.RECORDING_STATE.START,message.recordingId,null,null));else if("off"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,'Received request of "off" but the session is empty']);self._currentRecordingId=null,self._recordingStartInterval&&(clearTimeout(self._recordingStartInterval),log.warn(["MCU","Recording",message.recordingId,"Recording stopped abruptly before 4 seconds"]),self._recordingStartInterval=null),log.debug(["MCU","Recording",message.recordingId,"Stopped recording"]),self._recordings[message.recordingId].active=!1,self._recordings[message.recordingId].state=self.RECORDING_STATE.STOP,self._recordings[message.recordingId].endedDateTime=(new Date).toISOString(),self._trigger("recordingState",self.RECORDING_STATE.STOP,message.recordingId,null,null)}else if("url"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,"Received URL but the session is empty"]);var links={};if(Array.isArray(message.urls))for(var i=0;i"],recordingError);log.error(["MCU","Recording",message.recordingId,"Recording failure ->"],recordingError),self._recordings[message.recordingId].state=self.RECORDING_STATE.ERROR,self._recordings[message.recordingId].error=recordingError,self._recordings[message.recordingId].active&&(log.debug(["MCU","Recording",message.recordingId,"Stopped recording abruptly"]),self._recordings[message.recordingId].active=!1),self._trigger("recordingState",self.RECORDING_STATE.ERROR,message.recordingId,null,recordingError)}},Skylink.prototype._inRoomHandler=function(message){var self=this;log.log(["Server",null,message.type,"User is now in the room and functionalities are now available. Config received:"],message.pc_config),self._room.connection.peerConfig=self._setIceServers(message.pc_config),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.ENFORCE_OFFERER?2e15:-2e15),self._trigger("peerJoined",self._user.sid,self.getPeerInfo(),!0),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,self._user.sid);var streamId=null;self._streams.screenshare&&self._streams.screenshare.stream?(streamId=self._streams.screenshare.stream.id||self._streams.screenshare.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.screenshare.stream,!0,self.getPeerInfo(),!0,streamId)):self._streams.userMedia&&self._streams.userMedia.stream&&(streamId=self._streams.userMedia.stream.id||self._streams.userMedia.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.userMedia.stream,!0,self.getPeerInfo(),!1,streamId));var enterMsg={type:self._SIG_MESSAGE_TYPE.ENTER,mid:self._user.sid,rid:self._room.id,agent:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._enterHandler=function(message){var self=this,targetMid=message.mid,isNewPeer=!1,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),receiveOnly:self.getPeerInfo().config.receiveOnly,os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg),isNewPeer&&self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._restartHandler=function(message){var self=this,targetMid=message.mid,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg)}};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._offerHandler=function(message){var self=this,targetMid=message.mid,pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for offer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}log.log([targetMid,null,message.type,"Received offer from peer. Session description:"],clone(message));var offer={type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};return log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],offer),offer.sdp=self._removeSDPFilteredCandidates(targetMid,offer),offer.sdp=self._setSDPCodec(targetMid,offer),offer.sdp=self._setSDPBitrate(targetMid,offer),offer.sdp=self._setSDPCodecParams(targetMid,offer),offer.sdp=self._removeSDPCodecs(targetMid,offer),offer.sdp=self._removeSDPREMBPackets(targetMid,offer),offer.sdp=self._handleSDPConnectionSettings(targetMid,offer,"remote"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,null,message.type,'Peer connection state is not in "stable" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.resend}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),void pc.setRemoteDescription(new RTCSessionDescription(offer),function(){log.debug([targetMid,"RTCSessionDescription",message.type,"Remote description set"]),pc.setOffer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.OFFER,targetMid),self._addIceCandidateFromQueue(targetMid),self._doAnswer(targetMid)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,offer:offer})}))},Skylink.prototype._candidateHandler=function(message){var targetMid=message.mid;if(!message.candidate&&!message.id)return void log.warn([targetMid,"RTCIceCandidate",null,"Received invalid ICE candidate message ->"],message);var canId="can-"+(new Date).getTime(),candidateType=message.candidate.split(" ")[7]||"",candidate=new RTCIceCandidate({sdpMLineIndex:message.label,candidate:message.candidate,sdpMid:message.id});if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Received ICE candidate ->"],candidate),this._peerEndOfCandidatesCounter[targetMid]=this._peerEndOfCandidatesCounter[targetMid]||{},this._peerEndOfCandidatesCounter[targetMid].len=this._peerEndOfCandidatesCounter[targetMid].len||0,this._peerEndOfCandidatesCounter[targetMid].hasSet=!1,this._peerEndOfCandidatesCounter[targetMid].len++,this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.RECEIVED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!this._peerConnections[targetMid]||this._peerConnections[targetMid].signalingState===this.PEER_CONNECTION_STATE.CLOSED)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed.")),void this._signalingEndOfCandidates(targetMid);if(this._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._forceTURN)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping received ICE candidate as it matches ICE candidate filtering flag ->"],candidate),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Dropping of processing ICE candidate as it matches ICE candidate filtering flag.")),void this._signalingEndOfCandidates(targetMid);log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Not dropping received ICE candidate as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured ->"],candidate)}this._peerConnections[targetMid].remoteDescription&&this._peerConnections[targetMid].remoteDescription.sdp&&this._peerConnections[targetMid].localDescription&&this._peerConnections[targetMid].localDescription.sdp?this._addIceCandidate(targetMid,canId,candidate):this._addIceCandidateToQueue(targetMid,canId,candidate),this._signalingEndOfCandidates(targetMid),this._gatheredCandidates[targetMid]||(this._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),this._gatheredCandidates[targetMid].receiving[candidateType].push({sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex,candidate:candidate.candidate})},Skylink.prototype._answerHandler=function(message){var self=this,targetMid=message.mid;log.log([targetMid,null,message.type,"Received answer from peer. Session description:"],clone(message));var pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for answer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}var answer={type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};return log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],answer),answer.sdp=self._removeSDPFilteredCandidates(targetMid,answer),answer.sdp=self._setSDPCodec(targetMid,answer),answer.sdp=self._setSDPBitrate(targetMid,answer),answer.sdp=self._setSDPCodecParams(targetMid,answer),answer.sdp=self._removeSDPCodecs(targetMid,answer),answer.sdp=self._removeSDPREMBPackets(targetMid,answer),answer.sdp=self._handleSDPConnectionSettings(targetMid,answer,"remote"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?void log.warn([targetMid,null,message.type,'Peer connection state is not in "have-local-offer" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.restart}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),void pc.setRemoteDescription(new RTCSessionDescription(answer),function(){log.debug([targetMid,null,message.type,"Remote description set"]),pc.setAnswer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ANSWER,targetMid),self._addIceCandidateFromQueue(targetMid),self._peerMessagesStamps[targetMid]&&(self._peerMessagesStamps[targetMid].hasRestart=!1),self._dataChannels[targetMid]&&(-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))},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,answer:answer})}))},Skylink.prototype._isLowerThanVersion=function(agentVer,requiredVer){for(var partsA=(agentVer||"").split("."),partsB=(requiredVer||"").split("."),i=0;i0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for sendStream() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream);else{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"===window.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"===window.webrtcDetectedBrowser?(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio=getUserMediaAudioSettings):useMediaSource.indexOf("audio")>-1&&useMediaSource.indexOf("tab")>-1&&(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio={})),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if(hasDefaultAudioTrack||!enableAudioSettings)return void self._onStreamAccessSuccess(stream,settings,!0,!1);settings.getUserMediaSettings.audio=getUserMediaAudioSettings,navigator.getUserMedia({audio:getUserMediaAudioSettings},function(audioStream){try{audioStream.addTrack(stream.getVideoTracks()[0]),self.once("mediaAccessSuccess",function(){self._streams.screenshare.streamClone=stream},function(stream,isScreensharing){return isScreensharing}),self._onStreamAccessSuccess(audioStream,settings,!0,!1)}catch(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.shareScreen)},Skylink.prototype.stopScreen=function(){this._streams.screenshare&&(this._stopStreams({screenshare:!0}),this._inRoom&&(this._streams.userMedia&&this._streams.userMedia.stream&&(this._trigger("incomingStream",this._user.sid,this._streams.userMedia.stream,!0,this.getPeerInfo(),!1,this._streams.userMedia.stream.id||this._streams.userMedia.stream.label),this._trigger("peerUpdated",this._user.sid,this.getPeerInfo(),!0)),this._refreshPeerConnection(Object.keys(this._peerConnections),{},!1)))},Skylink.prototype._muteStreams=function(){var self=this,hasVideo=!1,hasAudio=!1,muteFn=function(stream){for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",self._streamsMutedSettings),{hasVideo:hasVideo,hasAudio:hasAudio}},Skylink.prototype._stopStreams=function(options){var self=this,stopFn=function(stream){var streamId=stream.id||stream.label;log.debug([null,"MediaStream",streamId,"Stopping Stream ->"],stream);try{for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",options)},Skylink.prototype._parseStreamSettings=function(options){var settings={settings:{audio:!1,video:!1},mutedSettings:{shouldAudioMuted:!1,shouldVideoMuted:!1},getUserMediaSettings:{audio:!1,video:!1}};return options.audio&&(settings.settings.audio={stereo:!1,exactConstraints:!!options.useExactConstraints,echoCancellation:!0},settings.getUserMediaSettings.audio={echoCancellation:!0},"object"==typeof options.audio&&("boolean"==typeof options.audio.stereo&&(settings.settings.audio.stereo=options.audio.stereo),"boolean"==typeof options.audio.useinbandfec&&(settings.settings.audio.useinbandfec=options.audio.useinbandfec),"boolean"==typeof options.audio.usedtx&&(settings.settings.audio.usedtx=options.audio.usedtx),"number"==typeof options.audio.maxplaybackrate&&options.audio.maxplaybackrate>=8e3&&options.audio.maxplaybackrate<=48e3&&(settings.settings.audio.maxplaybackrate=options.audio.maxplaybackrate),"boolean"==typeof options.audio.mute&&(settings.mutedSettings.shouldAudioMuted=options.audio.mute),"edge"!==window.webrtcDetectedBrowser&&("boolean"==typeof options.audio.echoCancellation&&(settings.settings.audio.echoCancellation=options.audio.echoCancellation,settings.getUserMediaSettings.audio.echoCancellation=options.audio.echoCancellation),Array.isArray(options.audio.optional)&&(settings.settings.audio.optional=clone(options.audio.optional),settings.getUserMediaSettings.audio.optional=clone(options.audio.optional)),options.audio.deviceId&&"string"==typeof options.audio.deviceId&&"firefox"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,settings.getUserMediaSettings.audio.deviceId=options.useExactConstraints?{exact:options.audio.deviceId}:{ideal:options.audio.deviceId}))),"edge"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio=!0)),options.video&&(settings.settings.video={resolution:clone(this.VIDEO_RESOLUTION.VGA),screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video={},"object"==typeof options.video?("boolean"==typeof options.video.mute&&(settings.mutedSettings.shouldVideoMuted=options.video.mute),Array.isArray(options.video.optional)&&(settings.settings.video.optional=clone(options.video.optional),settings.getUserMediaSettings.video.optional=clone(options.video.optional)),options.video.deviceId&&"string"==typeof options.video.deviceId&&"firefox"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,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&&!self._isUsingPlugin)&&(settings.settings.video.frameRate=options.video.frameRate,settings.getUserMediaSettings.video.frameRate="object"==typeof settings.settings.video.frameRate?settings.settings.video.frameRate:options.useExactConstraints?{exact:settings.settings.video.frameRate}:{max:settings.settings.video.frameRate}), -options.video.facingMode&&["string","object"].indexOf(typeof options.video.facingMode)>-1&&self._isUsingPlugin&&(settings.settings.video.facingMode=options.video.facingMode,settings.getUserMediaSettings.video.facingMode="object"==typeof settings.settings.video.facingMode?settings.settings.video.facingMode:options.useExactConstraints?{exact:settings.settings.video.facingMode}:{max:settings.settings.video.facingMode})):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"===window.webrtcDetectedBrowser&&(settings.settings.video={screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video=!0)),settings},Skylink.prototype._onStreamAccessSuccess=function(stream,settings,isScreenSharing,isAudioFallback){var self=this,streamId=stream.id||stream.label,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(window.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"===window.webrtcDetectedBrowser?stream.endedInterval=setInterval(function(){void 0===stream.recordedTime&&(stream.recordedTime=0),stream.recordedTime===stream.currentTime?(clearInterval(stream.endedInterval),self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])):stream.recordedTime=stream.currentTime},1e3):stream.onended=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},settings.settings.audio&&0===stream.getAudioTracks().length||settings.settings.video&&0===stream.getVideoTracks().length){var tracksNotSameError="Expected audio tracks length with "+(settings.settings.audio?"1":"0")+" and video tracks length with "+(settings.settings.video?"1":"0")+" but received audio tracks length with "+stream.getAudioTracks().length+" and video tracks length with "+stream.getVideoTracks().length;log.warn([null,"MediaStream",streamId,tracksNotSameError]);var requireAudio=!!settings.settings.audio,requireVideo=!!settings.settings.video;settings.settings.audio&&0===stream.getAudioTracks().length&&(settings.settings.audio=!1),settings.settings.video&&0===stream.getVideoTracks().length&&(settings.settings.video=!1),self._trigger("mediaAccessFallback",{error:new Error(tracksNotSameError),diff:{video:{expected:requireVideo?1:0,received:stream.getVideoTracks().length},audio:{expected:requireAudio?1:0,received:stream.getAudioTracks().length}}},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKED,!!isScreenSharing,!!isAudioFallback,streamId)}self._streams[isScreenSharing?"screenshare":"userMedia"]={stream:stream,settings:settings.settings,constraints:settings.getUserMediaSettings},self._muteStreams(),self._trigger("mediaAccessSuccess",stream,!!isScreenSharing,!!isAudioFallback,streamId)},Skylink.prototype._onStreamAccessError=function(error,settings,isScreenSharing){var self=this;if(!isScreenSharing&&settings.settings.audio&&settings.settings.video&&self._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},function(error){log.error("Failed fallbacking to retrieve audio only Stream ->",error),self._trigger("mediaAccessError",error,!1,!0),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.ERROR,!1,!0)});log.error("Failed retrieving "+(isScreenSharing?"screensharing":"camera")+" Stream ->",error),self._trigger("mediaAccessError",error,!!isScreenSharing,!1)},Skylink.prototype._onRemoteStreamAdded=function(targetMid,stream,isScreenSharing){var self=this;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1)},Skylink.prototype._addLocalMediaStreams=function(peerId){var self=this;try{log.log([peerId,null,null,"Adding local stream"]);var pc=self._peerConnections[peerId],offerToReceiveAudio=(self._peerInformations[peerId],self._peerInformations[peerId],!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-1?log.warn([peerId,null,null,"Not re-adding stream as LocalMediaStream is already added"],error):log.error([peerId,null,null,"Failed adding local stream"],error)}},Skylink.prototype._handleEndedStreams=function(peerId,checkStreamId){var self=this;self._streamsSession[peerId]=self._streamsSession[peerId]||{};var renderEndedFn=function(streamId){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){var codecsList=sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codecName+"/"+(samplingRate?samplingRate+("audio"===type?"[/]*.*":".*"):".*")+"\r\n","gi"));if(Array.isArray(codecsList)&&codecsList.length>0)for(var i=0;i0){for(var fmtpParts=(fmtpLine[0].split("a=fmtp:"+payload+" ")[1]||"").replace(/ /g,"").replace(/\r\n/g,"").split(";"),j=0;j0){if(0===sdpLines[i].indexOf("m="))break;0===sdpLines[i].indexOf("c=")?cLineIndex=i:0!==sdpLines[i].indexOf("b=AS:")&&0!==sdpLines[i].indexOf("b:TIAS:")||(sdpLines.splice(i,1),i--)}return"number"==typeof bw&&bw>0?-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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(this._peerInformations[targetMid],this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],compareB.join(" ")),sdpLines.splice(j,0,compareB.join(" ")),j++,mLineIndex++)}for(;this._sdpSessions[targetMid].remote.mLines[mLineIndex+1];){mLineIndex++;var appendIndex=sdpLines.length;sdpLines[appendIndex-1].replace(/\s/gi,"")||(appendIndex-=1);var parts=(this._sdpSessions[targetMid].remote.mLines[mLineIndex]||"").split(" ");parts[1]=0,log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending later rejected m= line ->"],parts.join(" ")),sdpLines.splice(appendIndex,0,parts.join(" "))}}return"edge"!==window.webrtcDetectedBrowser||sessionDescription.type!==this.HANDSHAKE_PROGRESS.OFFER||sdpLines[sdpLines.length-1].replace(/\s/gi,"")||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing last empty space for Edge browsers"]),sdpLines.splice(sdpLines.length-1,1)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "'+codec+'" as it does not exists.']);for(var i=0;i'],payload),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=fmtp:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:\\d+ rtx\\/\\d+\\r\\na=fmtp:\\d+ apt="+payload+"\\r\\n","g"),"");for(var sdpLines=sessionDescription.sdp.split("\r\n"),j=0;j=3&&parts.splice(parts.indexOf(payload),1),sdpLines[j]=parts.join(" ");break}sessionDescription.sdp=sdpLines.join("\r\n")}};return this._disableVideoFecCodecs&&(this._hasMCU?log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "ulpfec" or "red" codecs as connected to MCU to prevent connectivity issues.']):(parseFn("video","red"),parseFn("video","ulpfec"))),this._disableComfortNoiseCodec&&audioSettings&&"object"==typeof audioSettings&&audioSettings.stereo&&parseFn("audio","CN"),"edge"===window.webrtcDetectedBrowser&&"edge"!==(((this._peerInformations[targetMid]||{}).agent||{}).name||"unknown").name&&(sessionDescription.sdp=sessionDescription.sdp.replace(/a=rtcp-fb:.*\ x-message\ .*\r\n/gi,"")),sessionDescription.sdp},Skylink.prototype._removeSDPREMBPackets=function(targetMid,sessionDescription){return this._disableREMB?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing REMB packets."]),sessionDescription.sdp.replace(/a=rtcp-fb:\d+ goog-remb\r\n/g,"")):sessionDescription.sdp},Skylink.prototype._getSDPSelectedCodec=function(targetMid,sessionDescription,type,beSilentOnLogs){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},Skylink.prototype._removeSDPFilteredCandidates=function(targetMid,sessionDescription){return"MCU"===targetMid&&sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER&&"firefox"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=sessionDescription.sdp.replace(/ generation 0/g,""),sessionDescription.sdp=sessionDescription.sdp.replace(/ udp /g," UDP ")),this._forceTURN&&this._hasMCU?(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not filtering ICE candidates as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured"]),sessionDescription.sdp):(this._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._filterCandidatesType.relay&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "relay" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*relay.*\r\n/g,"")),sessionDescription.sdp)},Skylink.prototype._getCodecsSupport=function(callback){var self=this;if(self._currentCodecSupport)return void callback(null);self._currentCodecSupport={audio:{},video:{}};try{if("edge"===window.webrtcDetectedBrowser){for(var codecs=RTCRtpSender.getCapabilities().codecs,i=0;i-1&&codecs[i].name){var codec=codecs[i].name.toLowerCase();self._currentCodecSupport[codecs[i].kind][codec]=codecs[i].clockRate+(codecs[i].numChannels>1?"/"+codecs[i].numChannels:"")}callback(null)}else{var pc=new RTCPeerConnection(null),offerConstraints={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveVideo:!0,OfferToReceiveAudio:!0}});try{var channel=pc.createDataChannel("test");self._binaryChunkType=channel.binaryType||self._binaryChunkType,self._binaryChunkType=self._binaryChunkType.toLowerCase().indexOf("array")>-1?self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER:self._binaryChunkType;for(var prop in self.DATA_TRANSFER_DATA_TYPE)if(self.DATA_TRANSFER_DATA_TYPE.hasOwnProperty(prop)&&self._binaryChunkType.toLowerCase()===self.DATA_TRANSFER_DATA_TYPE[prop].toLowerCase()){self._binaryChunkType=self.DATA_TRANSFER_DATA_TYPE[prop];break}}catch(e){}pc.createOffer(function(offer){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",i=0;i"],sdpLines[i]),self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE&&bundleLineIndex>-1&&0===mLineIndex&&("remote"===direction?sessionDescription.type===this.HANDSHAKE_PROGRESS.OFFER:sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER)){log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not removing rejected m="+mediaType+" line ->"],sdpLines[i]),settings.connection[mediaType]=!0,["audio","video"].indexOf(mediaType)>-1&&(settings.direction[mediaType].send=!1,settings.direction[mediaType].receive=!1);continue}if("edge"===window.webrtcDetectedBrowser){sdpLines.splice(i,1),i--;continue}if("remote"===direction||sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER){var parts=sdpLines[i].split(" ");parts[1]=0,sdpLines[i]=parts.join(" ");continue}}if("remote"!==direction||0!==sdpLines[i].indexOf("a=candidate:")||self.getPeerInfo(targetMid).config.enableIceTrickle||sdpLines[i+1]&&(0===sdpLines[i+1].indexOf("a=candidate:")||0===sdpLines[i+1].indexOf("a=end-of-candidates"))||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]),sdpLines.splice(i+1,0,"a=end-of-candidates"),i++),mediaType)if(settings.connection[mediaType]){if(0===sdpLines[i].indexOf("a=mid:"))bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||"");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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"undefined"!=typeof exports?module.exports={Skylink:Skylink,SkylinkLogs:SkylinkLogs}:globals?(globals.Skylink=Skylink,globals.SkylinkLogs=SkylinkLogs):window&&(window.Skylink=Skylink,window.SkylinkLogs=SkylinkLogs)}(this); \ No newline at end of file +options.video.facingMode&&["string","object"].indexOf(typeof options.video.facingMode)>-1&&self._isUsingPlugin&&(settings.settings.video.facingMode=options.video.facingMode,settings.getUserMediaSettings.video.facingMode="object"==typeof settings.settings.video.facingMode?settings.settings.video.facingMode:options.useExactConstraints?{exact:settings.settings.video.facingMode}:{max:settings.settings.video.facingMode})):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"===window.webrtcDetectedBrowser&&(settings.settings.video={screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video=!0)),settings},Skylink.prototype._onStreamAccessSuccess=function(stream,settings,isScreenSharing,isAudioFallback){var self=this,streamId=stream.id||stream.label,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(window.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"===window.webrtcDetectedBrowser?stream.endedInterval=setInterval(function(){void 0===stream.recordedTime&&(stream.recordedTime=0),stream.recordedTime===stream.currentTime?(clearInterval(stream.endedInterval),self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])):stream.recordedTime=stream.currentTime},1e3):stream.onended=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},settings.settings.audio&&0===stream.getAudioTracks().length||settings.settings.video&&0===stream.getVideoTracks().length){var tracksNotSameError="Expected audio tracks length with "+(settings.settings.audio?"1":"0")+" and video tracks length with "+(settings.settings.video?"1":"0")+" but received audio tracks length with "+stream.getAudioTracks().length+" and video tracks length with "+stream.getVideoTracks().length;log.warn([null,"MediaStream",streamId,tracksNotSameError]);var requireAudio=!!settings.settings.audio,requireVideo=!!settings.settings.video;settings.settings.audio&&0===stream.getAudioTracks().length&&(settings.settings.audio=!1),settings.settings.video&&0===stream.getVideoTracks().length&&(settings.settings.video=!1),self._trigger("mediaAccessFallback",{error:new Error(tracksNotSameError),diff:{video:{expected:requireVideo?1:0,received:stream.getVideoTracks().length},audio:{expected:requireAudio?1:0,received:stream.getAudioTracks().length}}},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKED,!!isScreenSharing,!!isAudioFallback,streamId)}self._streams[isScreenSharing?"screenshare":"userMedia"]={stream:stream,settings:settings.settings,constraints:settings.getUserMediaSettings},self._muteStreams(),self._trigger("mediaAccessSuccess",stream,!!isScreenSharing,!!isAudioFallback,streamId)},Skylink.prototype._onStreamAccessError=function(error,settings,isScreenSharing){var self=this;if(!isScreenSharing&&settings.settings.audio&&settings.settings.video&&self._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},function(error){log.error("Failed fallbacking to retrieve audio only Stream ->",error),self._trigger("mediaAccessError",error,!1,!0),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.ERROR,!1,!0)});log.error("Failed retrieving "+(isScreenSharing?"screensharing":"camera")+" Stream ->",error),self._trigger("mediaAccessError",error,!!isScreenSharing,!1)},Skylink.prototype._onRemoteStreamAdded=function(targetMid,stream,isScreenSharing){var self=this;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1)},Skylink.prototype._addLocalMediaStreams=function(peerId){var self=this;try{log.log([peerId,null,null,"Adding local stream"]);var pc=self._peerConnections[peerId],offerToReceiveAudio=(self._peerInformations[peerId],self._peerInformations[peerId],!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-1?log.warn([peerId,null,null,"Not re-adding stream as LocalMediaStream is already added"],error):log.error([peerId,null,null,"Failed adding local stream"],error)}},Skylink.prototype._handleEndedStreams=function(peerId,checkStreamId){var self=this;self._streamsSession[peerId]=self._streamsSession[peerId]||{};var renderEndedFn=function(streamId){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){var codecsList=sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codecName+"/"+(samplingRate?samplingRate+("audio"===type?"[/]*.*":".*"):".*")+"\r\n","gi"));if(Array.isArray(codecsList)&&codecsList.length>0)for(var i=0;i0){for(var fmtpParts=(fmtpLine[0].split("a=fmtp:"+payload+" ")[1]||"").replace(/ /g,"").replace(/\r\n/g,"").split(";"),j=0;j0){if(0===sdpLines[i].indexOf("m="))break;0===sdpLines[i].indexOf("c=")?cLineIndex=i:0!==sdpLines[i].indexOf("b=AS:")&&0!==sdpLines[i].indexOf("b:TIAS:")||(sdpLines.splice(i,1),i--)}return"number"==typeof bw&&bw>0?-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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(this._peerInformations[targetMid],this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],compareB.join(" ")),sdpLines.splice(j,0,compareB.join(" ")),j++,mLineIndex++)}for(;this._sdpSessions[targetMid].remote.mLines[mLineIndex+1];){mLineIndex++;var appendIndex=sdpLines.length;sdpLines[appendIndex-1].replace(/\s/gi,"")||(appendIndex-=1);var parts=(this._sdpSessions[targetMid].remote.mLines[mLineIndex]||"").split(" ");parts[1]=0,log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending later rejected m= line ->"],parts.join(" ")),sdpLines.splice(appendIndex,0,parts.join(" "))}}return"edge"!==window.webrtcDetectedBrowser||sessionDescription.type!==this.HANDSHAKE_PROGRESS.OFFER||sdpLines[sdpLines.length-1].replace(/\s/gi,"")||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing last empty space for Edge browsers"]),sdpLines.splice(sdpLines.length-1,1)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "'+codec+'" as it does not exists.']);for(var i=0;i'],payload),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=fmtp:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:\\d+ rtx\\/\\d+\\r\\na=fmtp:\\d+ apt="+payload+"\\r\\n","g"),"");for(var sdpLines=sessionDescription.sdp.split("\r\n"),j=0;j=3&&parts.splice(parts.indexOf(payload),1),sdpLines[j]=parts.join(" ");break}sessionDescription.sdp=sdpLines.join("\r\n")}};return this._disableVideoFecCodecs&&(this._hasMCU?log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "ulpfec" or "red" codecs as connected to MCU to prevent connectivity issues.']):(parseFn("video","red"),parseFn("video","ulpfec"))),this._disableComfortNoiseCodec&&audioSettings&&"object"==typeof audioSettings&&audioSettings.stereo&&parseFn("audio","CN"),"edge"===window.webrtcDetectedBrowser&&"edge"!==(((this._peerInformations[targetMid]||{}).agent||{}).name||"unknown").name&&(sessionDescription.sdp=sessionDescription.sdp.replace(/a=rtcp-fb:.*\ x-message\ .*\r\n/gi,"")),sessionDescription.sdp},Skylink.prototype._removeSDPREMBPackets=function(targetMid,sessionDescription){return this._disableREMB?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing REMB packets."]),sessionDescription.sdp.replace(/a=rtcp-fb:\d+ goog-remb\r\n/g,"")):sessionDescription.sdp},Skylink.prototype._getSDPSelectedCodec=function(targetMid,sessionDescription,type,beSilentOnLogs){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},Skylink.prototype._removeSDPFilteredCandidates=function(targetMid,sessionDescription){return"MCU"===targetMid&&sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER&&"firefox"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=sessionDescription.sdp.replace(/ generation 0/g,""),sessionDescription.sdp=sessionDescription.sdp.replace(/ udp /g," UDP ")),this._forceTURN&&this._hasMCU?(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not filtering ICE candidates as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured"]),sessionDescription.sdp):(this._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._filterCandidatesType.relay&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "relay" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*relay.*\r\n/g,"")),sessionDescription.sdp)},Skylink.prototype._getCodecsSupport=function(callback){var self=this;if(self._currentCodecSupport)return void callback(null);self._currentCodecSupport={audio:{},video:{}};try{if("edge"===window.webrtcDetectedBrowser){for(var codecs=RTCRtpSender.getCapabilities().codecs,i=0;i-1&&codecs[i].name){var codec=codecs[i].name.toLowerCase();self._currentCodecSupport[codecs[i].kind][codec]=codecs[i].clockRate+(codecs[i].numChannels>1?"/"+codecs[i].numChannels:"")}callback(null)}else{var pc=new RTCPeerConnection(null),offerConstraints={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveVideo:!0,OfferToReceiveAudio:!0}});try{var channel=pc.createDataChannel("test");self._binaryChunkType=channel.binaryType||self._binaryChunkType,self._binaryChunkType=self._binaryChunkType.toLowerCase().indexOf("array")>-1?self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER:self._binaryChunkType;for(var prop in self.DATA_TRANSFER_DATA_TYPE)if(self.DATA_TRANSFER_DATA_TYPE.hasOwnProperty(prop)&&self._binaryChunkType.toLowerCase()===self.DATA_TRANSFER_DATA_TYPE[prop].toLowerCase()){self._binaryChunkType=self.DATA_TRANSFER_DATA_TYPE[prop];break}}catch(e){}pc.createOffer(function(offer){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",i=0;i"],sdpLines[i]),self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE&&bundleLineIndex>-1&&0===mLineIndex&&("remote"===direction?sessionDescription.type===this.HANDSHAKE_PROGRESS.OFFER:sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER)){log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not removing rejected m="+mediaType+" line ->"],sdpLines[i]),settings.connection[mediaType]=!0,["audio","video"].indexOf(mediaType)>-1&&(settings.direction[mediaType].send=!1,settings.direction[mediaType].receive=!1);continue}if("edge"===window.webrtcDetectedBrowser){sdpLines.splice(i,1),i--;continue}if("remote"===direction||sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER){var parts=sdpLines[i].split(" ");parts[1]=0,sdpLines[i]=parts.join(" ");continue}}if("remote"!==direction||0!==sdpLines[i].indexOf("a=candidate:")||self.getPeerInfo(targetMid).config.enableIceTrickle||sdpLines[i+1]&&(0===sdpLines[i+1].indexOf("a=candidate:")||0===sdpLines[i+1].indexOf("a=end-of-candidates"))||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]),sdpLines.splice(i+1,0,"a=end-of-candidates"),i++),mediaType)if(settings.connection[mediaType]){if(0===sdpLines[i].indexOf("a=mid:"))bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||"");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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"undefined"!=typeof exports?module.exports={Skylink:Skylink,SkylinkLogs:SkylinkLogs}:globals?(globals.Skylink=Skylink,globals.SkylinkLogs=SkylinkLogs):window&&(window.Skylink=Skylink,window.SkylinkLogs=SkylinkLogs)}(this); \ No newline at end of file diff --git a/publish/skylink.debug.js b/publish/skylink.debug.js index f4a3a98f7..30c201755 100644 --- a/publish/skylink.debug.js +++ b/publish/skylink.debug.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.23 - Thu Jun 15 2017 13:32:44 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.23 - Thu Jul 13 2017 18:37:09 GMT+0800 (SGT) */ (function(globals) { @@ -15718,10 +15718,11 @@ Skylink.prototype.RECORDING_STATE = { * options.audio.deviceId, options.audio.echoCancellation.
* The audio configuration options. * @param {Boolean} [options.audio.stereo=false]
Deprecation Warning! - * This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo + * This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo and + * the options.codecParams.audio.opus["sprop-stereo"] * parameter in the init() method instead. If the - * options.codecParams.audio.opus.stereo is configured, this overrides the - * options.audio.stereo setting.
+ * options.codecParams.audio.opus.stereo or options.codecParams.audio.opus["sprop-stereo"] + * is configured, this overrides the options.audio.stereo setting. * The flag if OPUS audio codec stereo band should be configured for sending encoded audio data. * When not provided, the default browser configuration is used. * @param {Boolean} [options.audio.usedtx]
Deprecation Warning! @@ -16587,10 +16588,11 @@ Skylink.prototype.disableVideo = function() { * @method shareScreen * @param {JSON|Boolean} [enableAudio=false] The flag if audio tracks should be retrieved. * @param {Boolean} [enableAudio.stereo=false]
Deprecation Warning! - * This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo + * This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo and + * the options.codecParams.audio.opus["sprop-stereo"] * parameter in the init() method instead. If the - * options.codecParams.audio.opus.stereo is configured, this overrides the - * options.audio.stereo setting.
+ * options.codecParams.audio.opus.stereo or options.codecParams.audio.opus["sprop-stereo"] + * is configured, this overrides the options.audio.stereo setting.
* The flag if OPUS audio codec stereo band should be configured for sending encoded audio data. * When not provided, the default browser configuration is used. * @param {Boolean} [enableAudio.usedtx]
Deprecation Warning! @@ -17713,6 +17715,11 @@ Skylink.prototype._setSDPCodecParams = function(targetMid, sessionDescription) { } else if (typeof audioSettings.stereo === 'boolean') { opusOptions.stereo = audioSettings.stereo; } + if (typeof self._codecParams.audio.opus['sprop-stereo'] === 'boolean') { + opusOptions['sprop-stereo'] = self._codecParams.audio.opus['sprop-stereo']; + } else if (typeof audioSettings.stereo === 'boolean') { + opusOptions['sprop-stereo'] = audioSettings.stereo; + } if (typeof self._codecParams.audio.opus.usedtx === 'boolean') { opusOptions.usedtx = self._codecParams.audio.opus.usedtx; } else if (typeof audioSettings.usedtx === 'boolean') { diff --git a/publish/skylink.min.js b/publish/skylink.min.js index 376c3092e..33c3967e8 100644 --- a/publish/skylink.min.js +++ b/publish/skylink.min.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.23 - 2017-06-15 */ +/*! skylinkjs - v0.6.23 - 2017-07-13 */ !function(globals){"use strict";function Skylink(){this._enableDataChannel=!0,this._dataChannels={},this._dataTransfers={},this._dataStreams={},this._peerCandidatesQueue={},this._peerEndOfCandidatesCounter={},this._gatheredCandidates={},this._filterCandidatesType={host:!1,srflx:!1,relay:!1},this._enableIceTrickle=!0,this._enableSTUN=!0,this._enableTURN=!0,this._usePublicSTUN=!0,this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},this._isUsingPlugin=!1,this._TURNTransport="any",this._peerInformations={},this._user=null,this._userData="",this._peerPriorityWeight=0,this._autoIntroduce=!0,this._isPrivileged=!1,this._peerList=null,this._selectedRoom=null,this._roomLocked=!1,this._inRoom=!1,this._EVENTS={},this._onceEvents={},this._timestamp={socketMessage:null,shareScreen:null,refreshConnection:null,getUserMedia:null,lastRestart:null},this._throttlingTimeouts={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},this._throttlingShouldThrowError=!1,this._socketSession={},this._socketMessageQueue=[],this._socketMessageTimeout=null,this._socketPorts={"http:":[80,3e3],"https:":[443,3443]},this._channelOpen=!1,this._signalingServer=null,this._signalingServerProtocol=window.location.protocol,this._signalingServerPort=null,this._socket=null,this._socketTimeout=2e4,this._socketUseXDR=!1,this._enableIceRestart="firefox"!==window.webrtcDetectedBrowser||window.webrtcDetectedVersion>=48,this._hasMCU=!1,this._forceSSL=!1,this._forceTURNSSL=!1,this._forceTURN=!1,this._path=null,this._roomServer="//api.temasys.io",this._appKey=null,this._defaultRoom=null,this._roomStart=null,this._roomDuration=null,this._roomCredentials=null,this._readyState=0,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._audioFallback=!1,this._streams={userMedia:null,screenshare:null},this._streamsDefaultSettings={userMedia:{audio:{stereo:!1},video:{resolution:{width:640,height:480},frameRate:50}},screenshare:{video:!0}},this._streamsMutedSettings={audioMuted:!1,videoMuted:!1},this._streamsBandwidthSettings={googleX:{},bAS:{}},this._streamsStoppedCbs={},this._streamsSession={},this._selectedAudioCodec="auto",this._selectedVideoCodec="auto",this._disableVideoFecCodecs=!1,this._disableComfortNoiseCodec=!1,this._disableREMB=!1,this._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},this._publishOnly=!1,this._parentId=null,this._recordings={},this._currentRecordingId=!1,this._recordingStartInterval=null,this._mcuUseRenegoRestart=!1,this._iceServer=null,this._socketServer=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType="firefox"===window.webrtcDetectedBrowser?this.DATA_TRANSFER_DATA_TYPE.BLOB:this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={},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;var clone=function(obj){if(null===obj||"object"!=typeof obj)return obj;var copy=function(data){var copy=data.constructor();for(var attr in data)data.hasOwnProperty(attr)&&(copy[attr]=data[attr]);return copy};if("object"==typeof obj&&!Array.isArray(obj))try{return JSON.parse(JSON.stringify(obj))}catch(err){return copy(obj)}return copy(obj)};Skylink.prototype.DATA_CHANNEL_STATE={CONNECTING:"connecting",OPEN:"open",CLOSING:"closing",CLOSED:"closed",ERROR:"error",CREATE_ERROR:"createError",BUFFERED_AMOUNT_LOW:"bufferedAmountLow",SEND_MESSAGE_ERROR:"sendMessageError"},Skylink.prototype.DATA_CHANNEL_TYPE={MESSAGING:"messaging",DATA:"data"},Skylink.prototype.DATA_CHANNEL_MESSAGE_ERROR={MESSAGE:"message",TRANSFER:"transfer"},Skylink.prototype._createDataChannel=function(peerId,dataChannel,bufferThreshold,createAsMessagingChannel){var self=this,channelName=(self._user&&self._user.sid?self._user.sid:"-")+"_"+peerId,channelType=createAsMessagingChannel?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,channelProp=channelType===self.DATA_CHANNEL_TYPE.MESSAGING?"main":channelName;if(!self._user)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as User does not have Room session"]);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as Peer connection does not exists"]);if(dataChannel&&"object"==typeof dataChannel?channelName=dataChannel.label:"string"==typeof dataChannel&&(channelName=dataChannel,dataChannel=null),!dataChannel)try{dataChannel=self._peerConnections[peerId].createDataChannel(channelName,{reliable:!0,ordered:!0})}catch(error){return log.error([peerId,"RTCDataChannel",channelProp,"Failed creating Datachannel ->"],error),void self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CREATE_ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))}self._dataChannels[peerId]?self._dataChannels[peerId].main&&self._dataChannels[peerId].main.channel.label===channelName&&(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING):(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING,self._dataChannels[peerId]={},log.debug([peerId,"RTCDataChannel",channelProp,"initializing main DataChannel"])),dataChannel.onerror=function(evt){var channelError=evt.error||evt;log.error([peerId,"RTCDataChannel",channelProp,"Datachannel has an exception ->"],channelError),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,channelError,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onbufferedamountlow=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel buffering data transfer low"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.BUFFERED_AMOUNT_LOW,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onmessage=function(event){self._processDataChannelData(event.data,peerId,channelName,channelType)};var onOpenHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has opened"]),dataChannel.bufferedAmountLowThreshold=bufferThreshold||0,self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.OPEN,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))};dataChannel.readyState===self.DATA_CHANNEL_STATE.OPEN?setTimeout(onOpenHandlerFn,1):(self._trigger("dataChannelState",dataChannel.readyState,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),dataChannel.onopen=onOpenHandlerFn);var onCloseHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has closed"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSED,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),self._peerConnections[peerId]&&self._peerConnections[peerId].remoteDescription&&self._peerConnections[peerId].remoteDescription.sdp&&(-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"===window.webrtcDetectedBrowser){var hasTriggeredClose=!1,timeBlockAfterClosing=0;dataChannel.onclose=function(){hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())};var onFFClosed=setInterval(function(){dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSED||hasTriggeredClose||5===timeBlockAfterClosing?(clearInterval(onFFClosed),hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())):dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSING&&timeBlockAfterClosing++},1e3)}else dataChannel.onclose=onCloseHandlerFn;channelType===self.DATA_CHANNEL_TYPE.MESSAGING?self._dataChannels[peerId].main={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}:self._dataChannels[peerId][channelName]={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}},Skylink.prototype._getDataChannelBuffer=function(peerId,channelProp){if("object"==typeof peerId)return{bufferedAmountLow:"number"==typeof peerId.bufferedAmountLow?peerId.bufferedAmountLow:parseInt(peerId.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof peerId.bufferedAmountLowThreshold?peerId.bufferedAmountLowThreshold:parseInt(peerId.bufferedAmountLowThreshold,10)||0};if(!(this._dataChannels[peerId]&&this._dataChannels[peerId][channelProp]&&this._dataChannels[peerId][channelProp].channel))return{bufferedAmountLow:0,bufferedAmountLowThreshold:0};var channel=this._dataChannels[peerId][channelProp].channel;return{bufferedAmountLow:"number"==typeof channel.bufferedAmountLow?channel.bufferedAmountLow:parseInt(channel.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof channel.bufferedAmountLowThreshold?channel.bufferedAmountLowThreshold:parseInt(channel.bufferedAmountLowThreshold,10)||0}},Skylink.prototype._sendMessageToDataChannel=function(peerId,data,channelProp,doNotConvert){var self=this;if(channelProp&&channelProp!==peerId||(channelProp="main"),!("object"==typeof data&&data||data&&"string"==typeof data))return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping invalid data ->"],data);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Peer connection does not exists or is closed ->"],data);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Datachannel connection does not exists ->"],data);var channelName=self._dataChannels[peerId][channelProp].channelName,channelType=self._dataChannels[peerId][channelProp].channelType,readyState=self._dataChannels[peerId][channelProp].channel.readyState,messageType="object"==typeof data&&data.type===self._DC_PROTOCOL_TYPE.MESSAGE?self.DATA_CHANNEL_MESSAGE_ERROR.MESSAGE:self.DATA_CHANNEL_MESSAGE_ERROR.TRANSFER;if(readyState!==self.DATA_CHANNEL_STATE.OPEN){var notOpenError='Failed sending message as Datachannel connection state is not opened. Current readyState is "'+readyState+'"';throw log.error([peerId,"RTCDataChannel",channelProp,notOpenError+" ->"],data),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,new Error(notOpenError),channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),new Error(notOpenError)}try{doNotConvert||"object"!=typeof data?(log.debug([peerId,"RTCDataChannel",channelProp,"Sending data with size ->"],data.size||data.length||data.byteLength),self._dataChannels[peerId][channelProp].channel.send(data)):(log.debug([peerId,"RTCDataChannel",channelProp,'Sending "'+data.type+'" protocol message ->'],data),self._dataChannels[peerId][channelProp].channel.send(JSON.stringify(data)))}catch(error){throw log.error([peerId,"RTCDataChannel",channelProp,"Failed sending "+(doNotConvert||"object"!=typeof data?"data":'"'+data.type+'" protocol message')+" ->"],error),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,error,channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),error}},Skylink.prototype._closeDataChannel=function(peerId,channelProp){var self=this;if(!self._dataChannels[peerId])return void log.warn([peerId,"RTCDataChannel",channelProp||null,"Aborting closing Datachannels as Peer connection does not have Datachannel sessions"]);var closeFn=function(rChannelProp){var channelName=self._dataChannels[peerId][rChannelProp].channelName,channelType=self._dataChannels[peerId][rChannelProp].channelType;self._dataChannels[peerId][rChannelProp].readyState!==self.DATA_CHANNEL_STATE.CLOSED&&(log.debug([peerId,"RTCDataChannel",channelProp,"Closing Datachannel"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSING,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(peerId,rChannelProp)),self._dataChannels[peerId][rChannelProp].channel.close(),delete self._dataChannels[peerId][rChannelProp])};if(channelProp){if(!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Aborting closing Datachannel as it does not exists"]);closeFn(channelProp)}else for(var channelNameProp in self._dataChannels)self._dataChannels[peerId].hasOwnProperty(channelNameProp)&&self._dataChannels[peerId][channelNameProp]&&closeFn(channelNameProp)},Skylink.prototype.DATA_TRANSFER_DATA_TYPE={BINARY_STRING:"binaryString",ARRAY_BUFFER:"arrayBuffer",BLOB:"blob",STRING:"string"},Skylink.prototype._CHUNK_FILE_SIZE=49152,Skylink.prototype._MOZ_CHUNK_FILE_SIZE=12288,Skylink.prototype._BINARY_FILE_SIZE=65456,Skylink.prototype._MOZ_BINARY_FILE_SIZE=16384,Skylink.prototype._CHUNK_DATAURL_SIZE=1212,Skylink.prototype._base64ToBlob=function(dataURL){for(var byteString=atob(dataURL),ab=new ArrayBuffer(byteString.length),ia=new Uint8Array(ab),j=0;jchunkSize){for(;blobByteSize-1>endCount;)endCount=startCount+chunkSize,chunksArray.push(blob.slice(startCount,endCount)),startCount+=chunkSize;blobByteSize-(startCount+1)>0&&chunksArray.push(blob.slice(startCount,blobByteSize-1))}else chunksArray.push(blob);return chunksArray},Skylink.prototype._chunkDataURL=function(dataURL,chunkSize){var outputStr=dataURL,dataURLArray=[],startCount=0,endCount=0,dataByteSize=dataURL.size||dataURL.length;if(dataByteSize>chunkSize){for(;dataByteSize-1>endCount;)endCount=startCount+chunkSize,dataURLArray.push(outputStr.slice(startCount,endCount)),startCount+=chunkSize;dataByteSize-(startCount+1)>0&&chunksArray.push(outputStr.slice(startCount,dataByteSize-1))}else dataURLArray.push(outputStr);return dataURLArray},Skylink.prototype.DT_PROTOCOL_VERSION="0.1.3",Skylink.prototype.DATA_TRANSFER_TYPE={UPLOAD:"upload",DOWNLOAD:"download"},Skylink.prototype.DATA_TRANSFER_SESSION_TYPE={BLOB:"blob",DATA_URL:"dataURL"},Skylink.prototype.DATA_TRANSFER_STATE={UPLOAD_REQUEST:"request",UPLOAD_STARTED:"uploadStarted",DOWNLOAD_STARTED:"downloadStarted",REJECTED:"rejected",CANCEL:"cancel",ERROR:"error",UPLOADING:"uploading",DOWNLOADING:"downloading",UPLOAD_COMPLETED:"uploadCompleted",DOWNLOAD_COMPLETED:"downloadCompleted",USER_REJECTED:"userRejected",USER_UPLOAD_REQUEST:"userRequest",START_ERROR:"startError"},Skylink.prototype.DATA_STREAM_STATE={SENDING_STARTED:"sendStart",SENDING_STOPPED:"sendStop",RECEIVING_STARTED:"receiveStart",RECEIVING_STOPPED:"receiveStop",RECEIVED:"received",SENT:"sent",ERROR:"error",START_ERROR:"startError"},Skylink.prototype._DC_PROTOCOL_TYPE={WRQ:"WRQ",ACK:"ACK",ERROR:"ERROR",CANCEL:"CANCEL",MESSAGE:"MESSAGE"},Skylink.prototype.sendBlobData=function(data,timeout,targetPeerId,sendChunksAsBinary,callback){this._startDataTransfer(data,timeout,targetPeerId,sendChunksAsBinary,callback,"blob")},Skylink.prototype.sendURLData=function(data,timeout,targetPeerId,callback){this._startDataTransfer(data,timeout,targetPeerId,callback,null,"data")},Skylink.prototype.respondBlobRequest=Skylink.prototype.acceptDataTransfer=function(peerId,transferId,accept){var self=this;if("string"!=typeof transferId&&"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as data transfer ID or peer ID is not provided"]);if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as Peer does not have any Datachannel connections"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as invalid transfer ID is provided"]);var channelProp="main";if(self._dataChannels[peerId][transferId]&&(channelProp=transferId),accept){log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]);var dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){console.info(evtPeerId,error,cN,cT),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD,message:new Error("Data transfer terminated as Peer Datachannel connection closed abruptly.")})};self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_STATE.MESSAGING:channelName===transferId)&&[self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED,self.DATA_CHANNEL_STATE.ERROR].indexOf(state)>-1:void self.off("dataChannelState",dataChannelStateCbFn)}),self.once("dataTransferState",function(){dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),delete self._dataTransfers[transferId],self._dataChannels[peerId]&&("main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),channelProp===transferId&&self._closeDataChannel(peerId,transferId))},function(state,evtTransferId,evtPeerId){return evtTransferId===transferId&&evtPeerId===peerId&&[self.DATA_TRANSFER_STATE.ERROR,self.DATA_TRANSFER_STATE.CANCEL,self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED].indexOf(state)>-1}),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:0},channelProp),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_STARTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)}else log.warn([peerId,"RTCDataChannel",transferId,"Rejected data transfer and data transfer request has been aborted"]),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:-1},channelProp),"main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.USER_REJECTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as User has rejected data transfer request."),transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD}),delete self._dataTransfers[transferId]},Skylink.prototype.cancelBlobTransfer=Skylink.prototype.cancelDataTransfer=function(peerId,transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer ID is not provided"]);if(!peerId||"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as peer ID is not provided"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer session does not exists."]);log.debug([peerId,"RTCDataChannel",transferId,"Canceling data transfer ..."]);var emitEventFn=function(peers,transferInfoPeerId){for(var i=0;i0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},"main"),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},transferId),emitEventFn(Object.keys(self._dataTransfers[transferId].peers.main).concat(Object.keys(self._dataTransfers[transferId].peers[transferId])))}else{var channelProp="main";if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as Peer does not have any Datachannel connections"]);self._dataChannels[peerId][transferId]&&(channelProp=transferId),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},channelProp),emitEventFn([peerId],peerId)}},Skylink.prototype.sendP2PMessage=function(message,targetPeerId){var listOfPeers=Object.keys(this._dataChannels),isPrivate=!1;if(Array.isArray(targetPeerId)?(listOfPeers=targetPeerId,isPrivate=!0):targetPeerId&&"string"==typeof targetPeerId&&(listOfPeers=[targetPeerId],isPrivate=!0),!this._inRoom||!this._user||!this._user.sid)return void log.error("Unable to send message as User is not in Room. ->",message);if(!this._enableDataChannel)return void log.error("Unable to send message as User does not have Datachannel enabled. ->",message);for(var i=0;i-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeStreamingFn=function(error){log.error(error)};if(!this._inRoom||!this._user||!this._user.sid)return emitErrorBeforeStreamingFn("Unable to start data streaming as User is not in Room.");if(!this._enableDataChannel)return emitErrorBeforeStreamingFn("Unable to start data streaming as User does not have Datachannel enabled.");if(0===listOfPeers.length)return emitErrorBeforeStreamingFn("Unable to start data streaming as there are no Peers to start session with.");if(self._hasMCU)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature is current not supported by MCU yet.");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},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"===window.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE)};if(peersNonInterop.length>0)if(self._hasMCU)waitForChannelOpenFn("MCU",peersNonInterop);else for(var pni=0;pni0)if(self._hasMCU)startDataSessionFn("MCU","main",peersInterop);else for(var pi=0;piself._CHUNK_DATAURL_SIZE:updatedDataChunk.length>self._BINARY_FILE_SIZE)return void log.error("Failed streaming data chunk as data chunk exceeds maximum chunk limit.");var sessionInfo={chunk:updatedDataChunk,chunkSize:updatedDataChunk.size||updatedDataChunk.length||updatedDataChunk.byteLength,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){var onSendDataFn=function(buffer){self._sendMessageToDataChannel(peerId,buffer,channelProp,!0);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i-1&&"string"!=typeof dataChunk?new Int8Array(dataChunk):dataChunk:new Blob([dataChunk]))};for(var peerId in self._dataStreams[transferId].sessions)if(self._dataStreams[transferId].sessions.hasOwnProperty(peerId)&&self._dataStreams[transferId].sessions[peerId]){var channelProp=self._dataStreams[transferId].sessions[peerId];if(!self._dataChannels[self._hasMCU?"MCU":peerId]||!self._dataChannels[self._hasMCU?"MCU":peerId][channelProp]||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].channel.readyState!==self.DATA_CHANNEL_STATE.OPEN||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].streamId!==transferId)return log.error([peerId,"RTCDataChannel",transferId,"Failed streaming data as it has not started or is ready."]),void self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,peerId,sessionInfo,new Error("Streaming as it has not started or Datachannel connection is not open."));self._hasMCU?"main"===channelProp?peersInterop.push(peerId):peersNonInterop.push(peerId):sendDataFn(peerId,channelProp)}self._hasMCU&&(peersInterop.length>0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype.stopStreamingData=function(transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error("Failed streaming data chunk as stream session ID is not provided.");if(!(self._inRoom&&self._user&&self._user.sid))return void log.error("Failed streaming data chunk as User is not in the Room.");if(!self._dataStreams[transferId])return void log.error("Failed stopping data streaming session as it does not exists.");if(!self._dataStreams[transferId].isUpload)return void log.error("Failed stopping data streaming session as it is not sending.");if(self._hasMCU)return void log.error("Failed stopping data streaming session as MCU does not support this feature yet.");var sessionInfo={chunk:null,chunkSize:0,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:transferId,size:0,originalSize:0,dataType:"fastBinaryStop",mimeType:null,chunkType:self._dataStreams[transferId].sessionChunkType,chunkSize:0,timeout:0,isPrivate:self._dataStreams[transferId].isPrivate,sender:self._user.sid,agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers||peerId},channelProp);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype._startDataTransfer=function(data,timeout,targetPeerId,sendChunksAsBinary,callback,sessionType){var self=this,transferId=(self._user?self._user.sid:"")+"_"+(new Date).getTime(),transferErrors={},transferCompleted=[],chunks=[],listOfPeers=Object.keys(self._peerConnections),sessionChunkType="string",transferInfo={name:null,size:null,chunkSize:null,chunkType:null,dataType:null,mimeType:null,direction:self.DATA_TRANSFER_TYPE.UPLOAD,timeout:60,isPrivate:!1,percentage:0};"number"==typeof timeout?transferInfo.timeout=timeout:Array.isArray(timeout)?listOfPeers=timeout:timeout&&"string"==typeof timeout?listOfPeers=[timeout]:timeout&&"boolean"==typeof timeout?sessionChunkType="binary":"function"==typeof timeout&&(callback=timeout),Array.isArray(targetPeerId)?listOfPeers=targetPeerId:targetPeerId&&"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:targetPeerId&&"boolean"==typeof targetPeerId?sessionChunkType="binary":"function"==typeof targetPeerId&&(callback=targetPeerId),sendChunksAsBinary&&"boolean"==typeof sendChunksAsBinary?sessionChunkType="binary":"function"==typeof sendChunksAsBinary&&(callback=sendChunksAsBinary),listOfPeers.indexOf("MCU")>-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeDataTransferFn=function(error){if(log.error(error),"function"==typeof callback){var transferErrors={};if(0===listOfPeers.length)transferErrors.self=new Error(error);else for(var i=0;i0){var bsChunkSize="firefox"===window.webrtcDetectedBrowser?self._MOZ_CHUNK_FILE_SIZE:self._CHUNK_FILE_SIZE,bsChunks=self._chunkBlobData(new Blob(chunks),bsChunkSize);self._dataTransfers[transferId].enforceBSInfo={chunkSize:4*Math.ceil(bsChunkSize/3),chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,size:4*Math.ceil(transferInfo.originalSize/3),chunks:bsChunks}}}for(var completeFn=function(peerId,error){transferCompleted.indexOf(peerId)>-1||(log.debug([peerId,"RTCDataChannel",transferId,"Data transfer result. Is errors present? ->"],error),transferCompleted.push(peerId),error&&(transferErrors[peerId]=new Error(error)),listOfPeers.length===transferCompleted.length&&(log.log([null,"RTCDataChannel",transferId,"Data transfer request completed"]),"function"==typeof callback&&(Object.keys(transferErrors).length>0?callback({transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),transferErrors:transferErrors,listOfPeers:listOfPeers},null):callback(null,{transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),listOfPeers:listOfPeers}))))},i=0;i0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,"main",Object.keys(self._dataTransfers[transferId].peers.main)),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,transferId,Object.keys(self._dataTransfers[transferId].peers[transferId])))},Skylink.prototype._startDataTransferToPeer=function(transferId,peerId,callback,channelProp,targetPeers){var self=this,peerConnectionStateCbFn=null,dataChannelStateCbFn=null,emitEventFn=function(cb){for(var peers=targetPeers||[peerId],i=0;i-1&&(log.warn([peerId,"RTCDataChannel",transferId,"Binary data chunks transfer is not yet supported with Peer connecting from Android, iOS and C++ SDK. Fallbacking to binary string data chunks transfer."]),size=self._dataTransfers[transferId].enforceBSInfo.size,chunkSize=self._dataTransfers[transferId].enforceBSInfo.chunkSize,chunkType="string"),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:self._dataTransfers[transferId].name,size:size,originalSize:self._dataTransfers[transferId].originalSize,dataType:self._dataTransfers[transferId].sessionType,mimeType:self._dataTransfers[transferId].mimeType,chunkType:chunkType,chunkSize:chunkSize,timeout:self._dataTransfers[transferId].timeout,isPrivate:self._dataTransfers[transferId].isPrivate,sender:self._user.sid,agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers||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");return self._isLowerThanVersion(protocolVer,"0.1.2")&&"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer do not support DATA_URL type of data transfers"):"MCU"!==peerId&&self._hasMCU?(channelProp=requireInterop?"main":transferId,peerConnectionStateCbFn=function(){returnErrorBeforeTransferFn("Data transfer terminated as Peer connection is not stable.")},self.once("peerConnectionState",peerConnectionStateCbFn,function(state,evtPeerId){return self._dataTransfers[transferId]?state!==self.PEER_CONNECTION_STATE.STABLE&&evtPeerId===peerId:void self.off("peerConnectionState",peerConnectionStateCbFn)}),requireInterop):(requireInterop||"main"===channelProp)&&self._dataChannels[peerId].main.transferId?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel has a data transfer in-progress."):(self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0},dataChannelStateCbFn=function(state,evtPeerId,error){self._dataTransfers[transferId].sessions[peerId].ackN>=self._dataTransfers[transferId].chunks.length-1||returnErrorBeforeTransferFn(error?error.message||error.toString():"Data transfer terminated as Peer Datachannel connection closed abruptly.")},self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName===transferId?(self._dataChannels[peerId][channelProp].transferId=transferId,sendWRQFn(),!1):[self.DATA_CHANNEL_STATE.CREATE_ERROR,self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1:void self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(self._dataChannels[peerId].main.transferId=transferId,sendWRQFn()):(channelProp=transferId,self._createDataChannel(peerId,transferId,"data"===self._dataTransfers[transferId].sessionType?self._CHUNK_DATAURL_SIZE:"string"===self._dataTransfers[transferId].sessionChunkType?"firefox"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE))))},Skylink.prototype._getTransferInfo=function(transferId,peerId,returnDataProp,hidePercentage,returnDataAtStart){if(!this._dataTransfers[transferId])return{};var transferInfo={name:this._dataTransfers[transferId].name,size:this._dataTransfers[transferId].size,dataType:this._dataTransfers[transferId].dataType||this.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:this._dataTransfers[transferId].mimeType||null,chunkSize:this._dataTransfers[transferId].chunkSize,chunkType:this._dataTransfers[transferId].chunkType,timeout:this._dataTransfers[transferId].timeout,isPrivate:this._dataTransfers[transferId].isPrivate,direction:this._dataTransfers[transferId].direction};if(this._dataTransfers[transferId].originalSize?transferInfo.size=this._dataTransfers[transferId].originalSize:this._dataTransfers[transferId].chunkType===this.DATA_TRANSFER_DATA_TYPE.BINARY_STRING&&(transferInfo.size=Math.ceil(3*transferInfo.size/4)),!hidePercentage){if(transferInfo.percentage=0,!this._dataTransfers[transferId].sessions[peerId])return returnDataProp&&(transferInfo.data=null),transferInfo;if(this._dataTransfers[transferId].direction===this.DATA_TRANSFER_TYPE.DOWNLOAD)this._dataTransfers[transferId].sessions[peerId].receivedSize===this._dataTransfers[transferId].sessions[peerId].size?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].receivedSize/this._dataTransfers[transferId].size*100).toFixed(2),10);else{var chunksLength=this._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?this._dataTransfers[transferId].enforceBSInfo.chunks.length:this._dataTransfers[transferId].chunks.length;this._dataTransfers[transferId].sessions[peerId].ackN===chunksLength?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].ackN/chunksLength*100).toFixed(2),10)}returnDataProp&&("number"!=typeof returnDataAtStart?100===transferInfo.percentage?transferInfo.data=this._getTransferData(transferId):transferInfo.data=null:(transferInfo.percentage=returnDataAtStart,0===returnDataAtStart&&(transferInfo.data=this._getTransferData(transferId))))}return transferInfo},Skylink.prototype._getTransferData=function(transferId){if(!this._dataTransfers[transferId])return null;if(this._dataTransfers[transferId].dataType===this.DATA_TRANSFER_SESSION_TYPE.BLOB){var mimeType={name:this._dataTransfers[transferId].name};return this._dataTransfers[transferId].mimeType&&(mimeType.type=this._dataTransfers[transferId].mimeType),new Blob(this._dataTransfers[transferId].chunks,mimeType)}return this._dataTransfers[transferId].chunks.join("")},Skylink.prototype._handleDataTransferTimeoutForPeer=function(transferId,peerId,setPeerTO){var self=this;if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer does not exists for Peer. Ignoring timeout."]);log.debug([peerId,"RTCDataChannel",transferId,"Clearing data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer&&clearTimeout(self._dataTransfers[transferId].sessions[peerId].timer),self._dataTransfers[transferId].sessions[peerId].timer=null,setPeerTO&&(log.debug([peerId,"RTCDataChannel",transferId,"Setting data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer=setTimeout(function(){if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer already ended for Peer. Ignoring expired timeout."]);if(!self._user||!self._user.sid)return void log.debug([peerId,"RTCDataChannel",transferId,"User is not in Room. Ignoring expired timeout."]);if(!self._dataChannels[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Datachannel connection does not exists. Ignoring expired timeout."]);log.error([peerId,"RTCDataChannel",transferId,"Data transfer response has timed out."]);var 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"===window.webrtcDetectedBrowser){if(window.BlobBuilder){var bb=new BlobBuilder;bb.append(rawData.constructor&&"ArrayBuffer"===rawData.constructor.name?byteArray:new Uint8Array(byteArray).buffer),blob=bb.getBlob()}}else blob=new Blob([byteArray]);log.debug([peerId,"RTCDataChannel",channelProp,"Received arraybuffer data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],blob.size),self._DATAProtocolHandler(peerId,blob,self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,blob.size,channelProp)}}},Skylink.prototype._WRQProtocolHandler=function(peerId,data,channelProp){var self=this,transferId="main"===channelProp?data.transferId||null:channelProp,senderPeerId=data.sender||peerId;if(["fastBinaryStart","fastBinaryStop"].indexOf(data.dataType)>-1)if("fastBinaryStart"===data.dataType){transferId||(transferId="stream_"+peerId+"_"+(new Date).getTime()),self._dataStreams[transferId]={chunkSize:0,chunkType:"string"===data.chunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:data.chunkType,isPrivate:!!data.isPrivate,isStringStream:"string"===data.chunkType,senderPeerId:senderPeerId,isUpload:!1},self._dataChannels[peerId][channelProp].streamId=transferId;self.once("dataChannelState",function(){},function(state,evtPeerId,channelName,channelType,error){if(!self._dataStreams[transferId])return!0;if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId&&channelType===self.DATA_CHANNEL_TYPE.DATA)&&[self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');return self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},updatedError),!0}}),self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STARTED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStarted",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1)}else transferId=self._dataChannels[peerId][channelProp].streamId,self._dataStreams[transferId]&&!self._dataStreams[transferId].isUpload&&(self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STOPPED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStopped",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1),self._dataChannels[peerId][channelProp].streamId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp),delete self._dataStreams[transferId]);else transferId||(transferId="transfer_"+peerId+"_"+(new Date).getTime()),self._dataTransfers[transferId]={name:data.name||transferId,size:data.size||0,chunkSize:data.chunkSize,originalSize:data.originalSize||0,timeout:data.timeout||60,isPrivate:!!data.isPrivate,senderPeerId:data.sender||peerId,dataType:self.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:data.mimeType||null,chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,direction:self.DATA_TRANSFER_TYPE.DOWNLOAD,chunks:[],sessions:{},sessionType:data.dataType||"blob",sessionChunkType:data.chunkType||"string"},"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?(self._dataTransfers[transferId].dataType=self.DATA_TRANSFER_SESSION_TYPE.DATA_URL,self._dataTransfers[transferId].chunkType=self.DATA_TRANSFER_DATA_TYPE.STRING):"blob"===self._dataTransfers[transferId].sessionType&&"binary"===self._dataTransfers[transferId].sessionChunkType&&(self._dataTransfers[transferId].chunkType=self._binaryChunkType),self._dataChannels[peerId][channelProp].transferId=transferId,self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0,receivedSize:0},self._trigger("incomingDataRequest",transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!1),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_REQUEST,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)},Skylink.prototype._ACKProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ACK event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};if(data.ackN>-1){if(0===data.ackN)emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_STARTED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,0),null)});else if(self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?data.ackN===self._dataTransfers[transferId].enforceBSInfo.chunks.length:data.ackN===self._dataTransfers[transferId].chunks.length)return self._dataTransfers[transferId].sessions[peerId].ackN=data.ackN,emitEventFn(function(evtPeerId){self._trigger("incomingData",self._getTransferData(transferId),transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,100),null)}),void(self._dataChannels[peerId][channelProp]&&(self._dataChannels[peerId][channelProp].transferId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp)));var uploadFn=function(chunk){self._sendMessageToDataChannel(peerId,chunk,channelProp,!0),data.ackN-1?self._blobToBase64(self._dataTransfers[transferId].enforceBSInfo.chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING?self._blobToBase64(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER?self._blobToArrayBuffer(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):uploadFn(self._dataTransfers[transferId].chunks[data.ackN])}else self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.REJECTED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as Peer has rejected data transfer request"),transferType:self.DATA_TRANSFER_TYPE.UPLOAD})},Skylink.prototype._MESSAGEProtocolHandler=function(peerId,data,channelProp){var senderPeerId=data.sender||peerId;log.log([senderPeerId,"RTCDataChannel",channelProp,"Received P2P message from peer:"],data),this._trigger("incomingMessage",{content:data.data,isPrivate:data.isPrivate,isDataChannel:!0,targetPeerId:this._user.sid,senderPeerId:senderPeerId},senderPeerId,this.getPeerInfo(senderPeerId),!1)},Skylink.prototype._ERRORProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,userInfo:self._getUserInfo(targetMid),target:targetMid,rid:self._room.id})}}},Skylink.prototype._addIceCandidateToQueue=function(targetMid,canId,candidate){var candidateType=candidate.candidate.split(" ")[7];log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Buffering ICE candidate."]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.BUFFERED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[],this._peerCandidatesQueue[targetMid].push([canId,candidate])},Skylink.prototype._addIceCandidateFromQueue=function(targetMid){this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[];for(var i=0;i"],error),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESS_ERROR,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},error)};if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Adding ICE candidate."]),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESSING,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[targetMid].remoteDescription&&self._peerConnections[targetMid].remoteDescription.sdp&&self._peerConnections[targetMid].remoteDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),void self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),-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"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}},refreshSinglePeer=function(peerId,peerCallback){ @@ -8,5 +8,5 @@ bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("numbe options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,maxplaybackrate:"number"==typeof options.codecParams.audio.opus.maxplaybackrate&&options.codecParams.audio.opus.maxplaybackrate>=8e3&&options.codecParams.audio.opus.maxplaybackrate<=48e3?options.codecParams.audio.opus.maxplaybackrate:null,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),!0===forceTURN&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,self._useEdgeWebRTC=useEdgeWebRTC,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}),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})):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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"Network error occurred. (Status: "+xhr.status+")",errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom)},xhr.onprogress=function(){log.debug([null,"XMLHttpRequest",method,"Retrieving information and config from webserver. Url:"],url),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},Skylink.prototype._parseInfo=function(info){if(log.log("Parsing parameter from server",info),!info.pc_constraints&&!info.offer_constraints)return void this._trigger("readyStateChange",this.READY_STATE_CHANGE.ERROR,{status:200,content:info.info,errorCode:info.error},self._selectedRoom);log.debug("Peer connection constraints:",info.pc_constraints),log.debug("Offer constraints:",info.offer_constraints),this._key=info.cid,this._appKeyOwner=info.apiOwner,this._signalingServer=info.ipSigserver,this._isPrivileged=info.isPrivileged,this._autoIntroduce=info.autoIntroduce,this._user={uid:info.username,token:info.userCred,timeStamp:info.timeStamp,streams:[],info:{}},this._room={id:info.room_key,token:info.roomCred,startDateTime:info.start,duration:info.len,connection:{peerConstraints:JSON.parse(info.pc_constraints),peerConfig:null,offerConstraints:JSON.parse(info.offer_constraints),sdpConstraints:{mandatory:{OfferToReceiveAudio:!0,OfferToReceiveVideo:!0}},mediaConstraints:JSON.parse(info.media_constraints)}},this._socketPorts={"http:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,this._trigger("readyStateChange",this.READY_STATE_CHANGE.COMPLETED,null,this._selectedRoom),log.info("Parsed parameters from webserver. Ready for web-realtime communication")},Skylink.prototype._loadInfo=function(){var self=this,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!function(){try{var p=new window.RTCPeerConnection(null);return["object","function"].indexOf(typeof p.createOffer)>-1&&null!==p.createOffer}catch(e){return!1}}())return window.RTCPeerConnection&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);self._getCodecsSupport(function(error){return error?(log.error(error),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:error.message||error.toString(),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):0===Object.keys(self._currentCodecSupport.audio).length&&0===Object.keys(self._currentCodecSupport.video).length?(log.error("No audio/video codecs available to start connection."),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No API Path is found",errorCode:self.READY_STATE_CHANGE_ERROR.NO_PATH},self._selectedRoom)):(log.error("XMLHttpRequest not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"XMLHttpRequest not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_XMLHTTPREQUEST_SUPPORT},self._selectedRoom)):(log.error("Socket.io not loaded. Please load socket.io"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"Socket.io not found",errorCode:self.READY_STATE_CHANGE_ERROR.NO_SOCKET_IO},self._selectedRoom))},Skylink.prototype._initSelectedRoom=function(room,callback){var self=this;if("function"==typeof room||void 0===room)return void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null,useEdgeWebRTC:self._useEdgeWebRTC};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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,target:message.target,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._redirectHandler=function(message){if(log.log(["Server",null,message.type,"System action warning:"],{message:message.info,reason:message.reason,action:message.action}),message.action===this.SYSTEM_ACTION.REJECT)for(var key in this._peerConnections)this._peerConnections.hasOwnProperty(key)&&this._removePeer(key);"toClose"===message.reason&&(message.reason="toclose"),this._trigger("systemAction",message.action,message.info,message.reason)},Skylink.prototype._updateUserEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer updated userData:"],message.userData),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].userData=message.stamp}this._peerInformations[targetMid].userData=message.userData||{},this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._roomLockEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,message.type,"Room lock status:"],message.lock),this._trigger("roomLock",message.lock,targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._muteAudioEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's audio muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].audioMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.audioMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,message.type,"Peer does not have any user information"])},Skylink.prototype._muteVideoEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's video muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].videoMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.videoMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._streamEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Peer's stream status:"],message.status),this._peerInformations[targetMid]&&message.streamId?(this._streamsSession[targetMid]=this._streamsSession[targetMid]||{},"ended"===message.status&&(message.settings&&"object"==typeof message.settings&&void 0===this._streamsSession[targetMid][message.streamId]&&(this._streamsSession[targetMid][message.streamId]={audio:message.settings.audio,video:message.settings.video}),this._handleEndedStreams(targetMid,message.streamId))):log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._byeHandler=function(message){var targetMid=message.mid;(this._user||{}).sid!==targetMid?(log.log([targetMid,null,message.type,"Peer has left the room"]),this._removePeer(targetMid)):log.log([targetMid,null,message.type,"Self has left the room"])},Skylink.prototype._privateMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received private message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!0,targetPeerId:message.target,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._publicMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received public message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!1,targetPeerId:null,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._recordingEventHandler=function(message){var self=this;if(log.debug(["MCU","Recording",null,"Received recording message ->"],message),"on"===message.action)self._recordings[message.recordingId]||(log.debug(["MCU","Recording",message.recordingId,"Started recording"]),self._currentRecordingId=message.recordingId,self._recordings[message.recordingId]={active:!0,state:self.RECORDING_STATE.START,startedDateTime:(new Date).toISOString(),endedDateTime:null,mixingDateTime:null,links:null,error:null},self._recordingStartInterval=setTimeout(function(){log.log(["MCU","Recording",message.recordingId,"4 seconds has been recorded. Recording can be stopped now"]),self._recordingStartInterval=null},4e3),self._trigger("recordingState",self.RECORDING_STATE.START,message.recordingId,null,null));else if("off"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,'Received request of "off" but the session is empty']);self._currentRecordingId=null,self._recordingStartInterval&&(clearTimeout(self._recordingStartInterval),log.warn(["MCU","Recording",message.recordingId,"Recording stopped abruptly before 4 seconds"]),self._recordingStartInterval=null),log.debug(["MCU","Recording",message.recordingId,"Stopped recording"]),self._recordings[message.recordingId].active=!1,self._recordings[message.recordingId].state=self.RECORDING_STATE.STOP,self._recordings[message.recordingId].endedDateTime=(new Date).toISOString(),self._trigger("recordingState",self.RECORDING_STATE.STOP,message.recordingId,null,null)}else if("url"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,"Received URL but the session is empty"]);var links={};if(Array.isArray(message.urls))for(var i=0;i"],recordingError);log.error(["MCU","Recording",message.recordingId,"Recording failure ->"],recordingError),self._recordings[message.recordingId].state=self.RECORDING_STATE.ERROR,self._recordings[message.recordingId].error=recordingError,self._recordings[message.recordingId].active&&(log.debug(["MCU","Recording",message.recordingId,"Stopped recording abruptly"]),self._recordings[message.recordingId].active=!1),self._trigger("recordingState",self.RECORDING_STATE.ERROR,message.recordingId,null,recordingError)}},Skylink.prototype._inRoomHandler=function(message){var self=this;log.log(["Server",null,message.type,"User is now in the room and functionalities are now available. Config received:"],message.pc_config),self._room.connection.peerConfig=self._setIceServers(message.pc_config),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.ENFORCE_OFFERER?2e15:-2e15),self._trigger("peerJoined",self._user.sid,self.getPeerInfo(),!0),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,self._user.sid);var streamId=null;self._streams.screenshare&&self._streams.screenshare.stream?(streamId=self._streams.screenshare.stream.id||self._streams.screenshare.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.screenshare.stream,!0,self.getPeerInfo(),!0,streamId)):self._streams.userMedia&&self._streams.userMedia.stream&&(streamId=self._streams.userMedia.stream.id||self._streams.userMedia.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.userMedia.stream,!0,self.getPeerInfo(),!1,streamId));var enterMsg={type:self._SIG_MESSAGE_TYPE.ENTER,mid:self._user.sid,rid:self._room.id,agent:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._enterHandler=function(message){var self=this,targetMid=message.mid,isNewPeer=!1,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),receiveOnly:self.getPeerInfo().config.receiveOnly,os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg),isNewPeer&&self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._restartHandler=function(message){var self=this,targetMid=message.mid,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg)}};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._offerHandler=function(message){var self=this,targetMid=message.mid,pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for offer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}log.log([targetMid,null,message.type,"Received offer from peer. Session description:"],clone(message));var offer={type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};return log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],offer),offer.sdp=self._removeSDPFilteredCandidates(targetMid,offer),offer.sdp=self._setSDPCodec(targetMid,offer),offer.sdp=self._setSDPBitrate(targetMid,offer),offer.sdp=self._setSDPCodecParams(targetMid,offer),offer.sdp=self._removeSDPCodecs(targetMid,offer),offer.sdp=self._removeSDPREMBPackets(targetMid,offer),offer.sdp=self._handleSDPConnectionSettings(targetMid,offer,"remote"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,null,message.type,'Peer connection state is not in "stable" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.resend}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),void pc.setRemoteDescription(new RTCSessionDescription(offer),function(){log.debug([targetMid,"RTCSessionDescription",message.type,"Remote description set"]),pc.setOffer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.OFFER,targetMid),self._addIceCandidateFromQueue(targetMid),self._doAnswer(targetMid)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,offer:offer})}))},Skylink.prototype._candidateHandler=function(message){var targetMid=message.mid;if(!message.candidate&&!message.id)return void log.warn([targetMid,"RTCIceCandidate",null,"Received invalid ICE candidate message ->"],message);var canId="can-"+(new Date).getTime(),candidateType=message.candidate.split(" ")[7]||"",candidate=new RTCIceCandidate({sdpMLineIndex:message.label,candidate:message.candidate,sdpMid:message.id});if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Received ICE candidate ->"],candidate),this._peerEndOfCandidatesCounter[targetMid]=this._peerEndOfCandidatesCounter[targetMid]||{},this._peerEndOfCandidatesCounter[targetMid].len=this._peerEndOfCandidatesCounter[targetMid].len||0,this._peerEndOfCandidatesCounter[targetMid].hasSet=!1,this._peerEndOfCandidatesCounter[targetMid].len++,this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.RECEIVED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!this._peerConnections[targetMid]||this._peerConnections[targetMid].signalingState===this.PEER_CONNECTION_STATE.CLOSED)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed.")),void this._signalingEndOfCandidates(targetMid);if(this._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._forceTURN)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping received ICE candidate as it matches ICE candidate filtering flag ->"],candidate),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Dropping of processing ICE candidate as it matches ICE candidate filtering flag.")),void this._signalingEndOfCandidates(targetMid);log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Not dropping received ICE candidate as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured ->"],candidate)}this._peerConnections[targetMid].remoteDescription&&this._peerConnections[targetMid].remoteDescription.sdp&&this._peerConnections[targetMid].localDescription&&this._peerConnections[targetMid].localDescription.sdp?this._addIceCandidate(targetMid,canId,candidate):this._addIceCandidateToQueue(targetMid,canId,candidate),this._signalingEndOfCandidates(targetMid),this._gatheredCandidates[targetMid]||(this._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),this._gatheredCandidates[targetMid].receiving[candidateType].push({sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex,candidate:candidate.candidate})},Skylink.prototype._answerHandler=function(message){var self=this,targetMid=message.mid;log.log([targetMid,null,message.type,"Received answer from peer. Session description:"],clone(message));var pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for answer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}var answer={type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};return log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],answer),answer.sdp=self._removeSDPFilteredCandidates(targetMid,answer),answer.sdp=self._setSDPCodec(targetMid,answer),answer.sdp=self._setSDPBitrate(targetMid,answer),answer.sdp=self._setSDPCodecParams(targetMid,answer),answer.sdp=self._removeSDPCodecs(targetMid,answer),answer.sdp=self._removeSDPREMBPackets(targetMid,answer),answer.sdp=self._handleSDPConnectionSettings(targetMid,answer,"remote"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?void log.warn([targetMid,null,message.type,'Peer connection state is not in "have-local-offer" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.restart}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),void pc.setRemoteDescription(new RTCSessionDescription(answer),function(){log.debug([targetMid,null,message.type,"Remote description set"]),pc.setAnswer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ANSWER,targetMid),self._addIceCandidateFromQueue(targetMid),self._peerMessagesStamps[targetMid]&&(self._peerMessagesStamps[targetMid].hasRestart=!1),self._dataChannels[targetMid]&&(-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))},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,answer:answer})}))},Skylink.prototype._isLowerThanVersion=function(agentVer,requiredVer){for(var partsA=(agentVer||"").split("."),partsB=(requiredVer||"").split("."),i=0;i0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for sendStream() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream);else{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"===window.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"===window.webrtcDetectedBrowser?(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio=getUserMediaAudioSettings):useMediaSource.indexOf("audio")>-1&&useMediaSource.indexOf("tab")>-1&&(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio={})),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if(hasDefaultAudioTrack||!enableAudioSettings)return void self._onStreamAccessSuccess(stream,settings,!0,!1);settings.getUserMediaSettings.audio=getUserMediaAudioSettings,navigator.getUserMedia({audio:getUserMediaAudioSettings},function(audioStream){try{audioStream.addTrack(stream.getVideoTracks()[0]),self.once("mediaAccessSuccess",function(){self._streams.screenshare.streamClone=stream},function(stream,isScreensharing){return isScreensharing}),self._onStreamAccessSuccess(audioStream,settings,!0,!1)}catch(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.shareScreen)},Skylink.prototype.stopScreen=function(){this._streams.screenshare&&(this._stopStreams({screenshare:!0}),this._inRoom&&(this._streams.userMedia&&this._streams.userMedia.stream&&(this._trigger("incomingStream",this._user.sid,this._streams.userMedia.stream,!0,this.getPeerInfo(),!1,this._streams.userMedia.stream.id||this._streams.userMedia.stream.label),this._trigger("peerUpdated",this._user.sid,this.getPeerInfo(),!0)),this._refreshPeerConnection(Object.keys(this._peerConnections),{},!1)))},Skylink.prototype._muteStreams=function(){var self=this,hasVideo=!1,hasAudio=!1,muteFn=function(stream){for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",self._streamsMutedSettings),{hasVideo:hasVideo,hasAudio:hasAudio}},Skylink.prototype._stopStreams=function(options){var self=this,stopFn=function(stream){var streamId=stream.id||stream.label;log.debug([null,"MediaStream",streamId,"Stopping Stream ->"],stream);try{for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",options)},Skylink.prototype._parseStreamSettings=function(options){var settings={settings:{audio:!1,video:!1},mutedSettings:{shouldAudioMuted:!1,shouldVideoMuted:!1},getUserMediaSettings:{audio:!1,video:!1}};return options.audio&&(settings.settings.audio={stereo:!1,exactConstraints:!!options.useExactConstraints,echoCancellation:!0},settings.getUserMediaSettings.audio={echoCancellation:!0},"object"==typeof options.audio&&("boolean"==typeof options.audio.stereo&&(settings.settings.audio.stereo=options.audio.stereo),"boolean"==typeof options.audio.useinbandfec&&(settings.settings.audio.useinbandfec=options.audio.useinbandfec),"boolean"==typeof options.audio.usedtx&&(settings.settings.audio.usedtx=options.audio.usedtx),"number"==typeof options.audio.maxplaybackrate&&options.audio.maxplaybackrate>=8e3&&options.audio.maxplaybackrate<=48e3&&(settings.settings.audio.maxplaybackrate=options.audio.maxplaybackrate),"boolean"==typeof options.audio.mute&&(settings.mutedSettings.shouldAudioMuted=options.audio.mute),"edge"!==window.webrtcDetectedBrowser&&("boolean"==typeof options.audio.echoCancellation&&(settings.settings.audio.echoCancellation=options.audio.echoCancellation,settings.getUserMediaSettings.audio.echoCancellation=options.audio.echoCancellation),Array.isArray(options.audio.optional)&&(settings.settings.audio.optional=clone(options.audio.optional),settings.getUserMediaSettings.audio.optional=clone(options.audio.optional)),options.audio.deviceId&&"string"==typeof options.audio.deviceId&&"firefox"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,settings.getUserMediaSettings.audio.deviceId=options.useExactConstraints?{exact:options.audio.deviceId}:{ideal:options.audio.deviceId}))),"edge"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio=!0)),options.video&&(settings.settings.video={resolution:clone(this.VIDEO_RESOLUTION.VGA),screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video={},"object"==typeof options.video?("boolean"==typeof options.video.mute&&(settings.mutedSettings.shouldVideoMuted=options.video.mute),Array.isArray(options.video.optional)&&(settings.settings.video.optional=clone(options.video.optional),settings.getUserMediaSettings.video.optional=clone(options.video.optional)),options.video.deviceId&&"string"==typeof options.video.deviceId&&"firefox"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,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&&!self._isUsingPlugin)&&(settings.settings.video.frameRate=options.video.frameRate,settings.getUserMediaSettings.video.frameRate="object"==typeof settings.settings.video.frameRate?settings.settings.video.frameRate:options.useExactConstraints?{exact:settings.settings.video.frameRate}:{max:settings.settings.video.frameRate}),options.video.facingMode&&["string","object"].indexOf(typeof options.video.facingMode)>-1&&self._isUsingPlugin&&(settings.settings.video.facingMode=options.video.facingMode,settings.getUserMediaSettings.video.facingMode="object"==typeof settings.settings.video.facingMode?settings.settings.video.facingMode:options.useExactConstraints?{exact:settings.settings.video.facingMode}:{max:settings.settings.video.facingMode})):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"===window.webrtcDetectedBrowser&&(settings.settings.video={screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video=!0)),settings},Skylink.prototype._onStreamAccessSuccess=function(stream,settings,isScreenSharing,isAudioFallback){var self=this,streamId=stream.id||stream.label,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(window.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"===window.webrtcDetectedBrowser?stream.endedInterval=setInterval(function(){void 0===stream.recordedTime&&(stream.recordedTime=0),stream.recordedTime===stream.currentTime?(clearInterval(stream.endedInterval),self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])):stream.recordedTime=stream.currentTime},1e3):stream.onended=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},settings.settings.audio&&0===stream.getAudioTracks().length||settings.settings.video&&0===stream.getVideoTracks().length){var tracksNotSameError="Expected audio tracks length with "+(settings.settings.audio?"1":"0")+" and video tracks length with "+(settings.settings.video?"1":"0")+" but received audio tracks length with "+stream.getAudioTracks().length+" and video tracks length with "+stream.getVideoTracks().length;log.warn([null,"MediaStream",streamId,tracksNotSameError]);var requireAudio=!!settings.settings.audio,requireVideo=!!settings.settings.video;settings.settings.audio&&0===stream.getAudioTracks().length&&(settings.settings.audio=!1),settings.settings.video&&0===stream.getVideoTracks().length&&(settings.settings.video=!1),self._trigger("mediaAccessFallback",{error:new Error(tracksNotSameError),diff:{video:{expected:requireVideo?1:0,received:stream.getVideoTracks().length},audio:{expected:requireAudio?1:0,received:stream.getAudioTracks().length}}},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKED,!!isScreenSharing,!!isAudioFallback,streamId)}self._streams[isScreenSharing?"screenshare":"userMedia"]={stream:stream,settings:settings.settings,constraints:settings.getUserMediaSettings},self._muteStreams(),self._trigger("mediaAccessSuccess",stream,!!isScreenSharing,!!isAudioFallback,streamId)},Skylink.prototype._onStreamAccessError=function(error,settings,isScreenSharing){var self=this;if(!isScreenSharing&&settings.settings.audio&&settings.settings.video&&self._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},function(error){log.error("Failed fallbacking to retrieve audio only Stream ->",error),self._trigger("mediaAccessError",error,!1,!0),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.ERROR,!1,!0)});log.error("Failed retrieving "+(isScreenSharing?"screensharing":"camera")+" Stream ->",error),self._trigger("mediaAccessError",error,!!isScreenSharing,!1)},Skylink.prototype._onRemoteStreamAdded=function(targetMid,stream,isScreenSharing){var self=this;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1)},Skylink.prototype._addLocalMediaStreams=function(peerId){var self=this;try{log.log([peerId,null,null,"Adding local stream"]);var pc=self._peerConnections[peerId],offerToReceiveAudio=(self._peerInformations[peerId],self._peerInformations[peerId],!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-1?log.warn([peerId,null,null,"Not re-adding stream as LocalMediaStream is already added"],error):log.error([peerId,null,null,"Failed adding local stream"],error)}},Skylink.prototype._handleEndedStreams=function(peerId,checkStreamId){var self=this;self._streamsSession[peerId]=self._streamsSession[peerId]||{};var renderEndedFn=function(streamId){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){var codecsList=sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codecName+"/"+(samplingRate?samplingRate+("audio"===type?"[/]*.*":".*"):".*")+"\r\n","gi"));if(Array.isArray(codecsList)&&codecsList.length>0)for(var i=0;i0){for(var fmtpParts=(fmtpLine[0].split("a=fmtp:"+payload+" ")[1]||"").replace(/ /g,"").replace(/\r\n/g,"").split(";"),j=0;j0){if(0===sdpLines[i].indexOf("m="))break;0===sdpLines[i].indexOf("c=")?cLineIndex=i:0!==sdpLines[i].indexOf("b=AS:")&&0!==sdpLines[i].indexOf("b:TIAS:")||(sdpLines.splice(i,1),i--)}return"number"==typeof bw&&bw>0?-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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(this._peerInformations[targetMid],this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],compareB.join(" ")),sdpLines.splice(j,0,compareB.join(" ")),j++,mLineIndex++)}for(;this._sdpSessions[targetMid].remote.mLines[mLineIndex+1];){mLineIndex++;var appendIndex=sdpLines.length;sdpLines[appendIndex-1].replace(/\s/gi,"")||(appendIndex-=1);var parts=(this._sdpSessions[targetMid].remote.mLines[mLineIndex]||"").split(" ");parts[1]=0,log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending later rejected m= line ->"],parts.join(" ")),sdpLines.splice(appendIndex,0,parts.join(" "))}}return"edge"!==window.webrtcDetectedBrowser||sessionDescription.type!==this.HANDSHAKE_PROGRESS.OFFER||sdpLines[sdpLines.length-1].replace(/\s/gi,"")||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing last empty space for Edge browsers"]),sdpLines.splice(sdpLines.length-1,1)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "'+codec+'" as it does not exists.']);for(var i=0;i'],payload),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=fmtp:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:\\d+ rtx\\/\\d+\\r\\na=fmtp:\\d+ apt="+payload+"\\r\\n","g"),"");for(var sdpLines=sessionDescription.sdp.split("\r\n"),j=0;j=3&&parts.splice(parts.indexOf(payload),1),sdpLines[j]=parts.join(" ");break}sessionDescription.sdp=sdpLines.join("\r\n")}};return this._disableVideoFecCodecs&&(this._hasMCU?log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "ulpfec" or "red" codecs as connected to MCU to prevent connectivity issues.']):(parseFn("video","red"),parseFn("video","ulpfec"))),this._disableComfortNoiseCodec&&audioSettings&&"object"==typeof audioSettings&&audioSettings.stereo&&parseFn("audio","CN"),"edge"===window.webrtcDetectedBrowser&&"edge"!==(((this._peerInformations[targetMid]||{}).agent||{}).name||"unknown").name&&(sessionDescription.sdp=sessionDescription.sdp.replace(/a=rtcp-fb:.*\ x-message\ .*\r\n/gi,"")),sessionDescription.sdp},Skylink.prototype._removeSDPREMBPackets=function(targetMid,sessionDescription){return this._disableREMB?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing REMB packets."]),sessionDescription.sdp.replace(/a=rtcp-fb:\d+ goog-remb\r\n/g,"")):sessionDescription.sdp},Skylink.prototype._getSDPSelectedCodec=function(targetMid,sessionDescription,type,beSilentOnLogs){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},Skylink.prototype._removeSDPFilteredCandidates=function(targetMid,sessionDescription){return"MCU"===targetMid&&sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER&&"firefox"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=sessionDescription.sdp.replace(/ generation 0/g,""),sessionDescription.sdp=sessionDescription.sdp.replace(/ udp /g," UDP ")),this._forceTURN&&this._hasMCU?(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not filtering ICE candidates as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured"]),sessionDescription.sdp):(this._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._filterCandidatesType.relay&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "relay" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*relay.*\r\n/g,"")),sessionDescription.sdp)},Skylink.prototype._getCodecsSupport=function(callback){var self=this;if(self._currentCodecSupport)return void callback(null);self._currentCodecSupport={audio:{},video:{}};try{if("edge"===window.webrtcDetectedBrowser){for(var codecs=RTCRtpSender.getCapabilities().codecs,i=0;i-1&&codecs[i].name){var codec=codecs[i].name.toLowerCase();self._currentCodecSupport[codecs[i].kind][codec]=codecs[i].clockRate+(codecs[i].numChannels>1?"/"+codecs[i].numChannels:"")}callback(null)}else{var pc=new RTCPeerConnection(null),offerConstraints={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveVideo:!0,OfferToReceiveAudio:!0}});try{var channel=pc.createDataChannel("test");self._binaryChunkType=channel.binaryType||self._binaryChunkType,self._binaryChunkType=self._binaryChunkType.toLowerCase().indexOf("array")>-1?self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER:self._binaryChunkType;for(var prop in self.DATA_TRANSFER_DATA_TYPE)if(self.DATA_TRANSFER_DATA_TYPE.hasOwnProperty(prop)&&self._binaryChunkType.toLowerCase()===self.DATA_TRANSFER_DATA_TYPE[prop].toLowerCase()){self._binaryChunkType=self.DATA_TRANSFER_DATA_TYPE[prop];break}}catch(e){}pc.createOffer(function(offer){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",i=0;i"],sdpLines[i]),self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE&&bundleLineIndex>-1&&0===mLineIndex&&("remote"===direction?sessionDescription.type===this.HANDSHAKE_PROGRESS.OFFER:sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER)){log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not removing rejected m="+mediaType+" line ->"],sdpLines[i]),settings.connection[mediaType]=!0,["audio","video"].indexOf(mediaType)>-1&&(settings.direction[mediaType].send=!1,settings.direction[mediaType].receive=!1);continue}if("edge"===window.webrtcDetectedBrowser){sdpLines.splice(i,1),i--;continue}if("remote"===direction||sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER){var parts=sdpLines[i].split(" ");parts[1]=0,sdpLines[i]=parts.join(" ");continue}}if("remote"!==direction||0!==sdpLines[i].indexOf("a=candidate:")||self.getPeerInfo(targetMid).config.enableIceTrickle||sdpLines[i+1]&&(0===sdpLines[i+1].indexOf("a=candidate:")||0===sdpLines[i+1].indexOf("a=end-of-candidates"))||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]),sdpLines.splice(i+1,0,"a=end-of-candidates"),i++),mediaType)if(settings.connection[mediaType]){if(0===sdpLines[i].indexOf("a=mid:"))bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||"");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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"undefined"!=typeof exports?module.exports={Skylink:Skylink,SkylinkLogs:SkylinkLogs}:globals?(globals.Skylink=Skylink,globals.SkylinkLogs=SkylinkLogs):window&&(window.Skylink=Skylink,window.SkylinkLogs=SkylinkLogs)}(this); \ No newline at end of file +(options.video.frameRate&&"object"==typeof options.video.frameRate||"number"==typeof options.video.frameRate&&!self._isUsingPlugin)&&(settings.settings.video.frameRate=options.video.frameRate,settings.getUserMediaSettings.video.frameRate="object"==typeof settings.settings.video.frameRate?settings.settings.video.frameRate:options.useExactConstraints?{exact:settings.settings.video.frameRate}:{max:settings.settings.video.frameRate}),options.video.facingMode&&["string","object"].indexOf(typeof options.video.facingMode)>-1&&self._isUsingPlugin&&(settings.settings.video.facingMode=options.video.facingMode,settings.getUserMediaSettings.video.facingMode="object"==typeof settings.settings.video.facingMode?settings.settings.video.facingMode:options.useExactConstraints?{exact:settings.settings.video.facingMode}:{max:settings.settings.video.facingMode})):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"===window.webrtcDetectedBrowser&&(settings.settings.video={screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video=!0)),settings},Skylink.prototype._onStreamAccessSuccess=function(stream,settings,isScreenSharing,isAudioFallback){var self=this,streamId=stream.id||stream.label,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(window.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"===window.webrtcDetectedBrowser?stream.endedInterval=setInterval(function(){void 0===stream.recordedTime&&(stream.recordedTime=0),stream.recordedTime===stream.currentTime?(clearInterval(stream.endedInterval),self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])):stream.recordedTime=stream.currentTime},1e3):stream.onended=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},settings.settings.audio&&0===stream.getAudioTracks().length||settings.settings.video&&0===stream.getVideoTracks().length){var tracksNotSameError="Expected audio tracks length with "+(settings.settings.audio?"1":"0")+" and video tracks length with "+(settings.settings.video?"1":"0")+" but received audio tracks length with "+stream.getAudioTracks().length+" and video tracks length with "+stream.getVideoTracks().length;log.warn([null,"MediaStream",streamId,tracksNotSameError]);var requireAudio=!!settings.settings.audio,requireVideo=!!settings.settings.video;settings.settings.audio&&0===stream.getAudioTracks().length&&(settings.settings.audio=!1),settings.settings.video&&0===stream.getVideoTracks().length&&(settings.settings.video=!1),self._trigger("mediaAccessFallback",{error:new Error(tracksNotSameError),diff:{video:{expected:requireVideo?1:0,received:stream.getVideoTracks().length},audio:{expected:requireAudio?1:0,received:stream.getAudioTracks().length}}},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKED,!!isScreenSharing,!!isAudioFallback,streamId)}self._streams[isScreenSharing?"screenshare":"userMedia"]={stream:stream,settings:settings.settings,constraints:settings.getUserMediaSettings},self._muteStreams(),self._trigger("mediaAccessSuccess",stream,!!isScreenSharing,!!isAudioFallback,streamId)},Skylink.prototype._onStreamAccessError=function(error,settings,isScreenSharing){var self=this;if(!isScreenSharing&&settings.settings.audio&&settings.settings.video&&self._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},function(error){log.error("Failed fallbacking to retrieve audio only Stream ->",error),self._trigger("mediaAccessError",error,!1,!0),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.ERROR,!1,!0)});log.error("Failed retrieving "+(isScreenSharing?"screensharing":"camera")+" Stream ->",error),self._trigger("mediaAccessError",error,!!isScreenSharing,!1)},Skylink.prototype._onRemoteStreamAdded=function(targetMid,stream,isScreenSharing){var self=this;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1)},Skylink.prototype._addLocalMediaStreams=function(peerId){var self=this;try{log.log([peerId,null,null,"Adding local stream"]);var pc=self._peerConnections[peerId],offerToReceiveAudio=(self._peerInformations[peerId],self._peerInformations[peerId],!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-1?log.warn([peerId,null,null,"Not re-adding stream as LocalMediaStream is already added"],error):log.error([peerId,null,null,"Failed adding local stream"],error)}},Skylink.prototype._handleEndedStreams=function(peerId,checkStreamId){var self=this;self._streamsSession[peerId]=self._streamsSession[peerId]||{};var renderEndedFn=function(streamId){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){var codecsList=sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codecName+"/"+(samplingRate?samplingRate+("audio"===type?"[/]*.*":".*"):".*")+"\r\n","gi"));if(Array.isArray(codecsList)&&codecsList.length>0)for(var i=0;i0){for(var fmtpParts=(fmtpLine[0].split("a=fmtp:"+payload+" ")[1]||"").replace(/ /g,"").replace(/\r\n/g,"").split(";"),j=0;j0){if(0===sdpLines[i].indexOf("m="))break;0===sdpLines[i].indexOf("c=")?cLineIndex=i:0!==sdpLines[i].indexOf("b=AS:")&&0!==sdpLines[i].indexOf("b:TIAS:")||(sdpLines.splice(i,1),i--)}return"number"==typeof bw&&bw>0?-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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(this._peerInformations[targetMid],this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],compareB.join(" ")),sdpLines.splice(j,0,compareB.join(" ")),j++,mLineIndex++)}for(;this._sdpSessions[targetMid].remote.mLines[mLineIndex+1];){mLineIndex++;var appendIndex=sdpLines.length;sdpLines[appendIndex-1].replace(/\s/gi,"")||(appendIndex-=1);var parts=(this._sdpSessions[targetMid].remote.mLines[mLineIndex]||"").split(" ");parts[1]=0,log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending later rejected m= line ->"],parts.join(" ")),sdpLines.splice(appendIndex,0,parts.join(" "))}}return"edge"!==window.webrtcDetectedBrowser||sessionDescription.type!==this.HANDSHAKE_PROGRESS.OFFER||sdpLines[sdpLines.length-1].replace(/\s/gi,"")||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing last empty space for Edge browsers"]),sdpLines.splice(sdpLines.length-1,1)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "'+codec+'" as it does not exists.']);for(var i=0;i'],payload),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=fmtp:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:\\d+ rtx\\/\\d+\\r\\na=fmtp:\\d+ apt="+payload+"\\r\\n","g"),"");for(var sdpLines=sessionDescription.sdp.split("\r\n"),j=0;j=3&&parts.splice(parts.indexOf(payload),1),sdpLines[j]=parts.join(" ");break}sessionDescription.sdp=sdpLines.join("\r\n")}};return this._disableVideoFecCodecs&&(this._hasMCU?log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "ulpfec" or "red" codecs as connected to MCU to prevent connectivity issues.']):(parseFn("video","red"),parseFn("video","ulpfec"))),this._disableComfortNoiseCodec&&audioSettings&&"object"==typeof audioSettings&&audioSettings.stereo&&parseFn("audio","CN"),"edge"===window.webrtcDetectedBrowser&&"edge"!==(((this._peerInformations[targetMid]||{}).agent||{}).name||"unknown").name&&(sessionDescription.sdp=sessionDescription.sdp.replace(/a=rtcp-fb:.*\ x-message\ .*\r\n/gi,"")),sessionDescription.sdp},Skylink.prototype._removeSDPREMBPackets=function(targetMid,sessionDescription){return this._disableREMB?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing REMB packets."]),sessionDescription.sdp.replace(/a=rtcp-fb:\d+ goog-remb\r\n/g,"")):sessionDescription.sdp},Skylink.prototype._getSDPSelectedCodec=function(targetMid,sessionDescription,type,beSilentOnLogs){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},Skylink.prototype._removeSDPFilteredCandidates=function(targetMid,sessionDescription){return"MCU"===targetMid&&sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER&&"firefox"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=sessionDescription.sdp.replace(/ generation 0/g,""),sessionDescription.sdp=sessionDescription.sdp.replace(/ udp /g," UDP ")),this._forceTURN&&this._hasMCU?(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not filtering ICE candidates as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured"]),sessionDescription.sdp):(this._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._filterCandidatesType.relay&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "relay" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*relay.*\r\n/g,"")),sessionDescription.sdp)},Skylink.prototype._getCodecsSupport=function(callback){var self=this;if(self._currentCodecSupport)return void callback(null);self._currentCodecSupport={audio:{},video:{}};try{if("edge"===window.webrtcDetectedBrowser){for(var codecs=RTCRtpSender.getCapabilities().codecs,i=0;i-1&&codecs[i].name){var codec=codecs[i].name.toLowerCase();self._currentCodecSupport[codecs[i].kind][codec]=codecs[i].clockRate+(codecs[i].numChannels>1?"/"+codecs[i].numChannels:"")}callback(null)}else{var pc=new RTCPeerConnection(null),offerConstraints={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveVideo:!0,OfferToReceiveAudio:!0}});try{var channel=pc.createDataChannel("test");self._binaryChunkType=channel.binaryType||self._binaryChunkType,self._binaryChunkType=self._binaryChunkType.toLowerCase().indexOf("array")>-1?self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER:self._binaryChunkType;for(var prop in self.DATA_TRANSFER_DATA_TYPE)if(self.DATA_TRANSFER_DATA_TYPE.hasOwnProperty(prop)&&self._binaryChunkType.toLowerCase()===self.DATA_TRANSFER_DATA_TYPE[prop].toLowerCase()){self._binaryChunkType=self.DATA_TRANSFER_DATA_TYPE[prop];break}}catch(e){}pc.createOffer(function(offer){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",i=0;i"],sdpLines[i]),self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE&&bundleLineIndex>-1&&0===mLineIndex&&("remote"===direction?sessionDescription.type===this.HANDSHAKE_PROGRESS.OFFER:sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER)){log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not removing rejected m="+mediaType+" line ->"],sdpLines[i]),settings.connection[mediaType]=!0,["audio","video"].indexOf(mediaType)>-1&&(settings.direction[mediaType].send=!1,settings.direction[mediaType].receive=!1);continue}if("edge"===window.webrtcDetectedBrowser){sdpLines.splice(i,1),i--;continue}if("remote"===direction||sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER){var parts=sdpLines[i].split(" ");parts[1]=0,sdpLines[i]=parts.join(" ");continue}}if("remote"!==direction||0!==sdpLines[i].indexOf("a=candidate:")||self.getPeerInfo(targetMid).config.enableIceTrickle||sdpLines[i+1]&&(0===sdpLines[i+1].indexOf("a=candidate:")||0===sdpLines[i+1].indexOf("a=end-of-candidates"))||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]),sdpLines.splice(i+1,0,"a=end-of-candidates"),i++),mediaType)if(settings.connection[mediaType]){if(0===sdpLines[i].indexOf("a=mid:"))bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||"");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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"undefined"!=typeof exports?module.exports={Skylink:Skylink,SkylinkLogs:SkylinkLogs}:globals?(globals.Skylink=Skylink,globals.SkylinkLogs=SkylinkLogs):window&&(window.Skylink=Skylink,window.SkylinkLogs=SkylinkLogs)}(this); \ No newline at end of file diff --git a/source/stream-media.js b/source/stream-media.js index 8057684a0..cb1b36026 100644 --- a/source/stream-media.js +++ b/source/stream-media.js @@ -298,10 +298,11 @@ Skylink.prototype.RECORDING_STATE = { * options.audio.deviceId, options.audio.echoCancellation.
* The audio configuration options. * @param {Boolean} [options.audio.stereo=false]
Deprecation Warning! - * This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo + * This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo and + * the options.codecParams.audio.opus["sprop-stereo"] * parameter in the init() method instead. If the - * options.codecParams.audio.opus.stereo is configured, this overrides the - * options.audio.stereo setting.
+ * options.codecParams.audio.opus.stereo or options.codecParams.audio.opus["sprop-stereo"] + * is configured, this overrides the options.audio.stereo setting. * The flag if OPUS audio codec stereo band should be configured for sending encoded audio data. * When not provided, the default browser configuration is used. * @param {Boolean} [options.audio.usedtx]
Deprecation Warning! @@ -1167,10 +1168,11 @@ Skylink.prototype.disableVideo = function() { * @method shareScreen * @param {JSON|Boolean} [enableAudio=false] The flag if audio tracks should be retrieved. * @param {Boolean} [enableAudio.stereo=false]
Deprecation Warning! - * This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo + * This property has been deprecated. Configure this with the options.codecParams.audio.opus.stereo and + * the options.codecParams.audio.opus["sprop-stereo"] * parameter in the init() method instead. If the - * options.codecParams.audio.opus.stereo is configured, this overrides the - * options.audio.stereo setting.
+ * options.codecParams.audio.opus.stereo or options.codecParams.audio.opus["sprop-stereo"] + * is configured, this overrides the options.audio.stereo setting.
* The flag if OPUS audio codec stereo band should be configured for sending encoded audio data. * When not provided, the default browser configuration is used. * @param {Boolean} [enableAudio.usedtx]
Deprecation Warning! diff --git a/source/stream-sdp.js b/source/stream-sdp.js index 59c4e258c..f86702339 100644 --- a/source/stream-sdp.js +++ b/source/stream-sdp.js @@ -71,6 +71,11 @@ Skylink.prototype._setSDPCodecParams = function(targetMid, sessionDescription) { } else if (typeof audioSettings.stereo === 'boolean') { opusOptions.stereo = audioSettings.stereo; } + if (typeof self._codecParams.audio.opus['sprop-stereo'] === 'boolean') { + opusOptions['sprop-stereo'] = self._codecParams.audio.opus['sprop-stereo']; + } else if (typeof audioSettings.stereo === 'boolean') { + opusOptions['sprop-stereo'] = audioSettings.stereo; + } if (typeof self._codecParams.audio.opus.usedtx === 'boolean') { opusOptions.usedtx = self._codecParams.audio.opus.usedtx; } else if (typeof audioSettings.usedtx === 'boolean') { From d61a2a81b19228ec3c08ff6b1e23bde29e9dd2fe Mon Sep 17 00:00:00 2001 From: Let Choo Date: Fri, 14 Jul 2017 22:09:28 +0800 Subject: [PATCH 2/6] ESS-911 Fixes for stereo and sprop-stereo audio codec option. --- doc/classes/Skylink.html | 51 ++++++++------ doc/data.json | 42 +++++++----- doc/files/source_room-init.js.html | 7 +- doc/files/source_stream-sdp.js.html | 3 +- publish/skylink.complete.js | 102 ++++++++++++++-------------- publish/skylink.complete.min.js | 32 ++++----- publish/skylink.debug.js | 12 ++-- publish/skylink.min.js | 8 +-- source/room-init.js | 7 +- source/stream-sdp.js | 3 +- 10 files changed, 148 insertions(+), 119 deletions(-) diff --git a/doc/classes/Skylink.html b/doc/classes/Skylink.html index c150be8f2..29f56e21f 100644 --- a/doc/classes/Skylink.html +++ b/doc/classes/Skylink.html @@ -4026,7 +4026,7 @@

_addSDPMediaStreamTrackIDs

-   Defined in: source/stream-sdp.js:411 +   Defined in: source/stream-sdp.js:412 @@ -6088,7 +6088,7 @@

_getCodecsSupport

-   Defined in: source/stream-sdp.js:801 +   Defined in: source/stream-sdp.js:802 @@ -6357,7 +6357,7 @@

_getSDPEdgeVideoSupports

-   Defined in: source/stream-sdp.js:1141 +   Defined in: source/stream-sdp.js:1142 @@ -6442,7 +6442,7 @@

_getSDPFingerprint

-   Defined in: source/stream-sdp.js:1103 +   Defined in: source/stream-sdp.js:1104 @@ -6527,7 +6527,7 @@

_getSDPSelectedCodec

-   Defined in: source/stream-sdp.js:702 +   Defined in: source/stream-sdp.js:703 @@ -7124,7 +7124,7 @@

_handleSDPConnectionSettings

-   Defined in: source/stream-sdp.js:894 +   Defined in: source/stream-sdp.js:895 @@ -7210,7 +7210,7 @@

_initSelectedRoom

-   Defined in: source/room-init.js:1339 +   Defined in: source/room-init.js:1342 @@ -7554,7 +7554,7 @@

_loadInfo

-   Defined in: source/room-init.js:1208 +   Defined in: source/room-init.js:1211 @@ -8668,7 +8668,7 @@

_parseInfo

-   Defined in: source/room-init.js:1138 +   Defined in: source/room-init.js:1141 @@ -9787,7 +9787,7 @@

_removeSDPCodecs

-   Defined in: source/stream-sdp.js:612 +   Defined in: source/stream-sdp.js:613 @@ -9872,7 +9872,7 @@

_removeSDPFilteredCandidates

-   Defined in: source/stream-sdp.js:759 +   Defined in: source/stream-sdp.js:760 @@ -9957,7 +9957,7 @@

_removeSDPFirefoxH264Pref

-   Defined in: source/stream-sdp.js:395 +   Defined in: source/stream-sdp.js:396 @@ -10044,7 +10044,7 @@

_removeSDPREMBPackets

-   Defined in: source/stream-sdp.js:686 +   Defined in: source/stream-sdp.js:687 @@ -10129,7 +10129,7 @@

_removeSDPUnknownAptRtx

-   Defined in: source/stream-sdp.js:557 +   Defined in: source/stream-sdp.js:558 @@ -10214,7 +10214,7 @@

_requestServerInfo

-   Defined in: source/room-init.js:1064 +   Defined in: source/room-init.js:1067 @@ -11076,7 +11076,7 @@

_setSDPBitrate

-   Defined in: source/stream-sdp.js:162 +   Defined in: source/stream-sdp.js:163 @@ -11162,7 +11162,7 @@

_setSDPCodec

-   Defined in: source/stream-sdp.js:298 +   Defined in: source/stream-sdp.js:299 @@ -16866,8 +16866,21 @@

Parameters:

- The flag if OPUS audio codec stereo band - should be configured for sending encoded audio data. + The flag if OPUS audio codec is able to decode or receive stereo packets. + When not provided, the default browser configuration is used. +
+ + +
  • + audio.opus.sprop-stereo + {Boolean} + + Optional + + +
    + + The flag if OPUS audio codec is sending stereo packets. When not provided, the default browser configuration is used.
  • diff --git a/doc/data.json b/doc/data.json index d80ccd5da..a8210f9d1 100644 --- a/doc/data.json +++ b/doc/data.json @@ -4768,7 +4768,13 @@ }, { "name": "audio.opus.stereo", - "description": "The flag if OPUS audio codec stereo band\n should be configured for sending encoded audio data.\n When not provided, the default browser configuration is used.", + "description": "The flag if OPUS audio codec is able to decode or receive stereo packets.\n When not provided, the default browser configuration is used.", + "type": "Boolean", + "optional": true + }, + { + "name": "audio.opus.sprop-stereo", + "description": "The flag if OPUS audio codec is sending stereo packets.\n When not provided, the default browser configuration is used.", "type": "Boolean", "optional": true }, @@ -5005,7 +5011,7 @@ }, { "file": "source/room-init.js", - "line": 1064, + "line": 1067, "description": "Starts retrieving Room credentials information from API server.", "itemtype": "method", "name": "_requestServerInfo", @@ -5016,7 +5022,7 @@ }, { "file": "source/room-init.js", - "line": 1138, + "line": 1141, "description": "Parses the Room credentials information retrieved from API server.", "itemtype": "method", "name": "_parseInfo", @@ -5027,7 +5033,7 @@ }, { "file": "source/room-init.js", - "line": 1208, + "line": 1211, "description": "Loads and checks the dependencies if they are loaded correctly.", "itemtype": "method", "name": "_loadInfo", @@ -5038,7 +5044,7 @@ }, { "file": "source/room-init.js", - "line": 1339, + "line": 1342, "description": "Starts initialising for Room credentials for room name provided in joinRoom() method.", "itemtype": "method", "name": "_initSelectedRoom", @@ -9951,7 +9957,7 @@ }, { "file": "source/stream-sdp.js", - "line": 162, + "line": 163, "description": "Function that modifies the session description to limit the maximum sending bandwidth.\nSetting this may not necessarily work in Firefox.", "itemtype": "method", "name": "_setSDPBitrate", @@ -9962,7 +9968,7 @@ }, { "file": "source/stream-sdp.js", - "line": 298, + "line": 299, "description": "Function that modifies the session description to set the preferred audio/video codec.", "itemtype": "method", "name": "_setSDPCodec", @@ -9973,7 +9979,7 @@ }, { "file": "source/stream-sdp.js", - "line": 395, + "line": 396, "description": "Function that modifies the session description to remove the previous experimental H264\ncodec that is apparently breaking connections.\nNOTE: We should perhaps not remove it since H264 is supported?", "itemtype": "method", "name": "_removeSDPFirefoxH264Pref", @@ -9984,7 +9990,7 @@ }, { "file": "source/stream-sdp.js", - "line": 411, + "line": 412, "description": "Function that modifies the session description to append the MediaStream and MediaStreamTrack IDs that seems\nto be missing from Firefox answer session description to Chrome connection causing freezes in re-negotiation.", "itemtype": "method", "name": "_addSDPMediaStreamTrackIDs", @@ -9995,7 +10001,7 @@ }, { "file": "source/stream-sdp.js", - "line": 557, + "line": 558, "description": "Function that modifies the session description to remove apt/rtx lines that does exists.", "itemtype": "method", "name": "_removeSDPUnknownAptRtx", @@ -10006,7 +10012,7 @@ }, { "file": "source/stream-sdp.js", - "line": 612, + "line": 613, "description": "Function that modifies the session description to remove codecs.", "itemtype": "method", "name": "_removeSDPCodecs", @@ -10017,7 +10023,7 @@ }, { "file": "source/stream-sdp.js", - "line": 686, + "line": 687, "description": "Function that modifies the session description to remove REMB packets fb.", "itemtype": "method", "name": "_removeSDPREMBPackets", @@ -10028,7 +10034,7 @@ }, { "file": "source/stream-sdp.js", - "line": 702, + "line": 703, "description": "Function that retrieves the session description selected codec.", "itemtype": "method", "name": "_getSDPSelectedCodec", @@ -10039,7 +10045,7 @@ }, { "file": "source/stream-sdp.js", - "line": 759, + "line": 760, "description": "Function that modifies the session description to remove non-relay ICE candidates.", "itemtype": "method", "name": "_removeSDPFilteredCandidates", @@ -10050,7 +10056,7 @@ }, { "file": "source/stream-sdp.js", - "line": 801, + "line": 802, "description": "Function that retrieves the current list of support codecs.", "itemtype": "method", "name": "_getCodecsSupport", @@ -10061,7 +10067,7 @@ }, { "file": "source/stream-sdp.js", - "line": 894, + "line": 895, "description": "Function that modifies the session description to handle the connection settings.\nThis is experimental and never recommended to end-users.", "itemtype": "method", "name": "_handleSDPConnectionSettings", @@ -10072,7 +10078,7 @@ }, { "file": "source/stream-sdp.js", - "line": 1103, + "line": 1104, "description": "Function that parses and retrieves the session description fingerprint.", "itemtype": "method", "name": "_getSDPFingerprint", @@ -10083,7 +10089,7 @@ }, { "file": "source/stream-sdp.js", - "line": 1141, + "line": 1142, "description": "Function that gets edge browser video supports.", "itemtype": "method", "name": "_getSDPEdgeVideoSupports", diff --git a/doc/files/source_room-init.js.html b/doc/files/source_room-init.js.html index 0ee9be74a..005096584 100644 --- a/doc/files/source_room-init.js.html +++ b/doc/files/source_room-init.js.html @@ -519,8 +519,9 @@

    File: source/room-init.js

    * @param {JSON} [options.codecParams.audio.opus] <blockquote class="info"> * Note that this is only applicable to OPUS audio codecs with a sampling rate of <code>48000</code> Hz (hertz). * </blockquote> The OPUS audio codec parameters to configure. - * @param {Boolean} [options.codecParams.audio.opus.stereo] The flag if OPUS audio codec stereo band - * should be configured for sending encoded audio data. + * @param {Boolean} [options.codecParams.audio.opus.stereo] The flag if OPUS audio codec is able to decode or receive stereo packets. + * <small>When not provided, the default browser configuration is used.</small> + * @param {Boolean} [options.codecParams.audio.opus.sprop-stereo] The flag if OPUS audio codec is sending stereo packets. * <small>When not provided, the default browser configuration is used.</small> * @param {Boolean} [options.codecParams.audio.opus.usedtx] <blockquote class="info"> * Note that this feature might not work depending on the browser support and implementation.</blockquote> @@ -919,6 +920,8 @@

    File: source/room-init.js

    codecParams.audio.opus = { stereo: typeof options.codecParams.audio.opus.stereo === 'boolean' ? options.codecParams.audio.opus.stereo : null, + 'sprop-stereo': typeof options.codecParams.audio.opus['sprop-stereo'] === 'boolean' ? + options.codecParams.audio.opus['sprop-stereo'] : null, usedtx: typeof options.codecParams.audio.opus.usedtx === 'boolean' ? options.codecParams.audio.opus.usedtx : null, useinbandfec: typeof options.codecParams.audio.opus.useinbandfec === 'boolean' ? diff --git a/doc/files/source_stream-sdp.js.html b/doc/files/source_stream-sdp.js.html index eb0412ffc..b02d6e697 100644 --- a/doc/files/source_stream-sdp.js.html +++ b/doc/files/source_stream-sdp.js.html @@ -155,7 +155,8 @@

    File: source/stream-sdp.js

    // RFC: https://tools.ietf.org/html/draft-ietf-payload-rtp-opus-11 parseFn('audio', self.AUDIO_CODEC.OPUS, 48000, (function () { var opusOptions = {}; - var audioSettings = self.getPeerInfo().settings.audio; + var audioSettings = self._streams.screenshare ? self._streams.screenshare.settings.audio : + (self._streams.userMedia ? self._streams.userMedia.settings.audio : {}); audioSettings = audioSettings && typeof audioSettings === 'object' ? audioSettings : {}; if (typeof self._codecParams.audio.opus.stereo === 'boolean') { opusOptions.stereo = self._codecParams.audio.opus.stereo; diff --git a/publish/skylink.complete.js b/publish/skylink.complete.js index 638985175..e7592596f 100644 --- a/publish/skylink.complete.js +++ b/publish/skylink.complete.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.23 - Thu Jul 13 2017 18:37:09 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.23 - Fri Jul 14 2017 22:08:48 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 ? parts[0].split('/')[1] : 'sendrecv', uri: parts[1] }; }; @@ -8040,7 +8044,10 @@ SDPUtils.parseExtmap = function(line) { // RTCRtpHeaderExtension. SDPUtils.writeExtmap = function(headerExtension) { return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) + - ' ' + headerExtension.uri + '\r\n'; + (headerExtension.direction && headerExtension.direction !== 'sendrecv' + ? '/' + headerExtension.direction + : '') + + ' ' + headerExtension.uri + '\r\n'; }; // Parses an ftmp line, returns dictionary. Sample input: @@ -8127,26 +8134,26 @@ SDPUtils.getMid = function(mediaSection) { } } +SDPUtils.parseFingerprint = function(line) { + var parts = line.substr(14).split(' '); + return { + algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge. + value: parts[1] + }; +}; + // Extracts DTLS parameters from SDP media section or sessionpart. // FIXME: for consistency with other functions this should only // get the fingerprint line as input. See also getIceParameters. SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.splitLines(mediaSection); - // Search in session part, too. - lines = lines.concat(SDPUtils.splitLines(sessionpart)); - var fpLine = lines.filter(function(line) { - return line.indexOf('a=fingerprint:') === 0; - })[0].substr(14); + var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, + 'a=fingerprint:'); // Note: a=setup line is ignored since we use the 'auto' role. // Note2: 'algorithm' is not case sensitive except in Edge. - var dtlsParameters = { + return { role: 'auto', - fingerprints: [{ - algorithm: fpLine.split(' ')[0].toLowerCase(), - value: fpLine.split(' ')[1] - }] + fingerprints: lines.map(SDPUtils.parseFingerprint) }; - return dtlsParameters; }; // Serializes DTLS parameters to SDP. @@ -8371,7 +8378,7 @@ SDPUtils.parseRtcpParameters = function(mediaSection) { return rtcpParameters; }; -// parses either a=msid: or a=ssrc:... msid lines an returns +// parses either a=msid: or a=ssrc:... msid lines and returns // the id of the MediaStream and MediaStreamTrack. SDPUtils.parseMsid = function(mediaSection) { var parts; @@ -8415,7 +8422,9 @@ SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) { sdp += 'a=mid:' + transceiver.mid + '\r\n'; - if (transceiver.rtpSender && transceiver.rtpReceiver) { + if (transceiver.direction) { + sdp += 'a=' + transceiver.direction + '\r\n'; + } else if (transceiver.rtpSender && transceiver.rtpReceiver) { sdp += 'a=sendrecv\r\n'; } else if (transceiver.rtpSender) { sdp += 'a=sendonly\r\n'; @@ -11122,11 +11131,7 @@ module.exports = { } var cc = {}; Object.keys(c).forEach(function(key) { - if (key === 'require' || key === 'advanced') { - return; - } - if (typeof c[key] === 'string') { - cc[key] = c[key]; + if (key === 'require' || key === 'advanced' || key === 'mediaSource') { return; } var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]}; @@ -11139,15 +11144,6 @@ module.exports = { } return (name === 'deviceId') ? 'sourceId' : name; }; - - // HACK : Specially handling: if deviceId is an object with exact property, - // change it such that deviceId value is not in exact property - // Reason : AJS-286 (deviceId in WebRTC samples not in the format specified as specifications) - if ( oldname('', key) === 'sourceId' && r.exact !== undefined ) { - r.ideal = r.exact; - r.exact = undefined; - } - if (r.ideal !== undefined) { cc.optional = cc.optional || []; var oc = {}; @@ -11931,25 +11927,24 @@ AdapterJS._defineMediaSourcePolyfill = function () { // Check if screensharing feature is available if (!!AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature && !!AdapterJS.WebRTCPlugin.plugin.isScreensharingAvailable) { // Do strict checks for the source ID - "screen", "window" or ["screen", "window"] - // Note that the screen/window can be JS selected using constraints.video.optional[n].screenId + var sourceId = AdapterJS.WebRTCPlugin.plugin.screensharingKey || 'Screensharing'; if (AdapterJS.WebRTCPlugin.plugin.screensharingKeys) { // Param: ["screen", "window"] - // Legacy: Also s upport for "Screensharing" and "screensharing" - 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 - ) { + if (Array.isArray(updatedConstraints.video.mediaSource) && + updatedConstraints.video.mediaSource.indexOf('screen') > -1 && + updatedConstraints.video.mediaSource.indexOf('window') > -1) { + sourceId = AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screenOrWindow; updatedConstraints.video.mediaSource = AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screenOrWindow; // Param: ["screen"] or "screen" } else if ((Array.isArray(updatedConstraints.video.mediaSource) && updatedConstraints.video.mediaSource.indexOf('screen') > -1) || updatedConstraints.video.mediaSource === 'screen') { + sourceId = AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screen; updatedConstraints.video.mediaSource = AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screen; // Param: ["window"] or "window" } else if ((Array.isArray(updatedConstraints.video.mediaSource) && updatedConstraints.video.mediaSource.indexOf('window') > -1) || updatedConstraints.video.mediaSource === 'window') { + sourceId = AdapterJS.WebRTCPlugin.plugin.screensharingKeys.window; updatedConstraints.video.mediaSource = AdapterJS.WebRTCPlugin.plugin.screensharingKeys.window; } else { failureCb(new Error('GetUserMedia: Only "screen", "window", ["screen", "window"] are supported as mediaSource constraints')); @@ -11957,9 +11952,8 @@ AdapterJS._defineMediaSourcePolyfill = function () { } } - // Support for legacy plugins : set the sourceId to the mediaSource value updatedConstraints.video.optional = updatedConstraints.video.optional || []; - updatedConstraints.video.optional.push({ sourceId: updatedConstraints.video.mediaSource }); + updatedConstraints.video.optional.push({ sourceId: sourceId }); baseGetUserMedia(updatedConstraints, successCb, failureCb); @@ -11983,7 +11977,7 @@ AdapterJS._defineMediaSourcePolyfill = function () { if (typeof window.require !== 'function') { AdapterJS._defineMediaSourcePolyfill(); } -/*! skylinkjs - v0.6.23 - Thu Jul 13 2017 18:37:09 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.23 - Fri Jul 14 2017 22:08:48 GMT+0800 (+08) */ (function(globals) { @@ -22139,8 +22133,9 @@ Skylink.prototype.generateUUID = function() { * @param {JSON} [options.codecParams.audio.opus]
    * Note that this is only applicable to OPUS audio codecs with a sampling rate of 48000 Hz (hertz). *
    The OPUS audio codec parameters to configure. - * @param {Boolean} [options.codecParams.audio.opus.stereo] The flag if OPUS audio codec stereo band - * should be configured for sending encoded audio data. + * @param {Boolean} [options.codecParams.audio.opus.stereo] The flag if OPUS audio codec is able to decode or receive stereo packets. + * When not provided, the default browser configuration is used. + * @param {Boolean} [options.codecParams.audio.opus.sprop-stereo] The flag if OPUS audio codec is sending stereo packets. * When not provided, the default browser configuration is used. * @param {Boolean} [options.codecParams.audio.opus.usedtx]
    * Note that this feature might not work depending on the browser support and implementation.
    @@ -22539,6 +22534,8 @@ Skylink.prototype.init = function(options, callback) { codecParams.audio.opus = { stereo: typeof options.codecParams.audio.opus.stereo === 'boolean' ? options.codecParams.audio.opus.stereo : null, + 'sprop-stereo': typeof options.codecParams.audio.opus['sprop-stereo'] === 'boolean' ? + options.codecParams.audio.opus['sprop-stereo'] : null, usedtx: typeof options.codecParams.audio.opus.usedtx === 'boolean' ? options.codecParams.audio.opus.usedtx : null, useinbandfec: typeof options.codecParams.audio.opus.useinbandfec === 'boolean' ? @@ -29693,7 +29690,8 @@ Skylink.prototype._setSDPCodecParams = function(targetMid, sessionDescription) { // RFC: https://tools.ietf.org/html/draft-ietf-payload-rtp-opus-11 parseFn('audio', self.AUDIO_CODEC.OPUS, 48000, (function () { var opusOptions = {}; - var audioSettings = self.getPeerInfo().settings.audio; + var audioSettings = self._streams.screenshare ? self._streams.screenshare.settings.audio : + (self._streams.userMedia ? self._streams.userMedia.settings.audio : {}); audioSettings = audioSettings && typeof audioSettings === 'object' ? audioSettings : {}; if (typeof self._codecParams.audio.opus.stereo === 'boolean') { opusOptions.stereo = self._codecParams.audio.opus.stereo; diff --git a/publish/skylink.complete.min.js b/publish/skylink.complete.min.js index 35f1aed47..c2bb2c7d0 100644 --- a/publish/skylink.complete.min.js +++ b/publish/skylink.complete.min.js @@ -1,18 +1,18 @@ -/*! skylinkjs - v0.6.23 - 2017-07-13 */ +/*! skylinkjs - v0.6.23 - 2017-07-14 */ !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;i=0)hasMatch=navigator.userAgent.match(/OPR\/(\d+)/i)||[],webrtcDetectedBrowser="opera",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=26,webrtcDetectedType="webkit",webrtcDetectedDCSupport="SCTP";else if(navigator.userAgent.match(/Bowser\/[0-9.]*/g)){hasMatch=navigator.userAgent.match(/Bowser\/[0-9.]*/g)||[];var chromiumVersion=parseInt((navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./i)||[])[2]||"0",10);webrtcDetectedBrowser="bowser",webrtcDetectedVersion=parseFloat((hasMatch[0]||"0/0").split("/")[1],10),webrtcMinimumVersion=0,webrtcDetectedType="webkit",webrtcDetectedDCSupport=chromiumVersion>30?"SCTP":"RTP"}else if(navigator.userAgent.indexOf("OPiOS")>0)hasMatch=navigator.userAgent.match(/OPiOS\/([0-9]+)\./),webrtcDetectedBrowser="opera",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=0,webrtcDetectedType=null,webrtcDetectedDCSupport=null;else if(navigator.userAgent.indexOf("CriOS")>0)hasMatch=navigator.userAgent.match(/CriOS\/([0-9]+)\./)||[],webrtcDetectedBrowser="chrome",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=0,webrtcDetectedType=null,webrtcDetectedDCSupport=null;else if(navigator.userAgent.indexOf("FxiOS")>0)hasMatch=navigator.userAgent.match(/FxiOS\/([0-9]+)\./)||[],webrtcDetectedBrowser="firefox",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=0,webrtcDetectedType=null,webrtcDetectedDCSupport=null;else if(document.documentMode)hasMatch=/\brv[ :]+(\d+)/g.exec(navigator.userAgent)||[],webrtcDetectedBrowser="IE",webrtcDetectedVersion=parseInt(hasMatch[1],10),webrtcMinimumVersion=9,webrtcDetectedType="plugin",webrtcDetectedDCSupport="SCTP",webrtcDetectedVersion||(hasMatch=/\bMSIE[ :]+(\d+)/g.exec(navigator.userAgent)||[],webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10));else if(window.StyleMedia||navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))hasMatch=navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)||[],webrtcDetectedBrowser="edge",webrtcDetectedVersion=parseFloat((hasMatch[0]||"0/0").split("/")[1],10),webrtcMinimumVersion=13.10547,webrtcDetectedType="ms",webrtcDetectedDCSupport=null;else if("undefined"!=typeof InstallTrigger||navigator.userAgent.indexOf("irefox")>0)hasMatch=navigator.userAgent.match(/Firefox\/([0-9]+)\./)||[],webrtcDetectedBrowser="firefox",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=33,webrtcDetectedType="moz",webrtcDetectedDCSupport="SCTP";else if(window.chrome&&window.chrome.webstore||navigator.userAgent.indexOf("Chrom")>0)hasMatch=navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./i)||[],webrtcDetectedBrowser="chrome",webrtcDetectedVersion=parseInt(hasMatch[2]||"0",10),webrtcMinimumVersion=38,webrtcDetectedType="webkit",webrtcDetectedDCSupport=webrtcDetectedVersion>30?"SCTP":"RTP";else if(/^((?!chrome|android).)*safari/i.test(navigator.userAgent)){hasMatch=navigator.userAgent.match(/version\/(\d+)/i)||[];var isMobile=navigator.userAgent.match(/(iPhone|iPad)/gi)||[];webrtcDetectedBrowser="safari",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=7,webrtcDetectedType=0===isMobile.length?"plugin":null,webrtcDetectedDCSupport=0===isMobile.length?"SCTP":null}window.webrtcDetectedBrowser=webrtcDetectedBrowser,window.webrtcDetectedVersion=webrtcDetectedVersion,window.webrtcMinimumVersion=webrtcMinimumVersion,window.webrtcDetectedType=webrtcDetectedType,window.webrtcDetectedDCSupport=webrtcDetectedDCSupport},AdapterJS.addEvent=function(elem,evnt,func){elem.addEventListener?elem.addEventListener(evnt,func,!1):elem.attachEvent?elem.attachEvent("on"+evnt,func):elem[evnt]=func},AdapterJS.renderNotificationBar=function(message,buttonText,buttonCallback){if("complete"===document.readyState){var w=window,i=document.createElement("iframe");i.name="adapterjs-alert",i.style.position="fixed",i.style.top="-41px",i.style.left=0,i.style.right=0,i.style.width="100%",i.style.height="40px",i.style.backgroundColor="#ffffe1",i.style.border="none",i.style.borderBottom="1px solid #888888",i.style.zIndex="9999999","string"==typeof i.style.webkitTransition?i.style.webkitTransition="all .5s ease-out":"string"==typeof i.style.transition&&(i.style.transition="all .5s ease-out"),document.body.appendChild(i);var c=i.contentWindow?i.contentWindow:i.contentDocument.document?i.contentDocument.document:i.contentDocument;c.document.open(),c.document.write(''+message+""),buttonText&&"function"==typeof buttonCallback?(c.document.write(''),c.document.close(),AdapterJS.addEvent(c.document.getElementById("okay"),"click",function(e){e.preventDefault();try{e.cancelBubble=!0}catch(error){}buttonCallback(e)}),AdapterJS.addEvent(c.document.getElementById("cancel"),"click",function(e){w.document.body.removeChild(i)})):c.document.close(),setTimeout(function(){"string"==typeof i.style.webkitTransform?i.style.webkitTransform="translateY(40px)":"string"==typeof i.style.transform?i.style.transform="translateY(40px)":i.style.top="0px"},300)}},webrtcDetectedType=null,checkMediaDataChannelSettings=function(peerBrowserAgent,peerBrowserVersion,callback,constraints){if("function"==typeof callback){var beOfferer=!0,isLocalFirefox="firefox"===webrtcDetectedBrowser,isLocalFirefoxInterop="moz"===webrtcDetectedType&&webrtcDetectedVersion>30,isPeerFirefox="firefox"===peerBrowserAgent;if(isLocalFirefox&&isPeerFirefox||isLocalFirefoxInterop)try{delete constraints.mandatory.MozDontOfferDataChannel}catch(error){console.error("Failed deleting MozDontOfferDataChannel"),console.error(error)}else isLocalFirefox&&!isPeerFirefox&&(constraints.mandatory.MozDontOfferDataChannel=!0);if(!isLocalFirefox)for(var prop in constraints.mandatory)constraints.mandatory.hasOwnProperty(prop)&&-1!==prop.indexOf("Moz")&&delete constraints.mandatory[prop];!isLocalFirefox||isPeerFirefox||isLocalFirefoxInterop||(beOfferer=!1),callback(beOfferer,constraints)}},checkIceConnectionState=function(peerId,iceConnectionState,callback){if("function"!=typeof callback)return void console.warn("No callback specified in checkIceConnectionState. Aborted.");peerId=peerId||"peer",AdapterJS._iceConnectionFiredStates[peerId]&&iceConnectionState!==AdapterJS._iceConnectionStates.disconnected&&iceConnectionState!==AdapterJS._iceConnectionStates.failed&&iceConnectionState!==AdapterJS._iceConnectionStates.closed||(AdapterJS._iceConnectionFiredStates[peerId]=[]),iceConnectionState=AdapterJS._iceConnectionStates[iceConnectionState],AdapterJS._iceConnectionFiredStates[peerId].indexOf(iceConnectionState)<0&&(AdapterJS._iceConnectionFiredStates[peerId].push(iceConnectionState),iceConnectionState===AdapterJS._iceConnectionStates.connected&&setTimeout(function(){AdapterJS._iceConnectionFiredStates[peerId].push(AdapterJS._iceConnectionStates.done),callback(AdapterJS._iceConnectionStates.done)},1e3),callback(iceConnectionState))},createIceServer=null,createIceServers=null,MediaStream="function"==typeof MediaStream?MediaStream:null,RTCPeerConnection="function"==typeof RTCPeerConnection?RTCPeerConnection:null,RTCSessionDescription="function"==typeof RTCSessionDescription?RTCSessionDescription:null,RTCIceCandidate="function"==typeof RTCIceCandidate?RTCIceCandidate:null,getUserMedia=null,attachMediaStream=null,reattachMediaStream=null,webrtcDetectedBrowser=null,webrtcDetectedVersion=null,webrtcMinimumVersion=null,!(navigator.mozGetUserMedia||navigator.webkitGetUserMedia||navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))||0===(navigator.userAgent.match(/android/gi)||[]).length&&0===(navigator.userAgent.match(/chrome/gi)||[]).length&&navigator.userAgent.indexOf("Safari/")>0?("object"==typeof console&&"function"==typeof console.log||(console={}||console,console.log=function(arg){},console.info=function(arg){},console.error=function(arg){},console.dir=function(arg){},console.exception=function(arg){},console.trace=function(arg){},console.warn=function(arg){},console.count=function(arg){},console.debug=function(arg){},console.count=function(arg){},console.time=function(arg){},console.timeEnd=function(arg){},console.group=function(arg){},console.groupCollapsed=function(arg){},console.groupEnd=function(arg){}),AdapterJS.parseWebrtcDetectedBrowser(),isIE="IE"===webrtcDetectedBrowser,AdapterJS.WebRTCPlugin.WaitForPluginReady=function(){for(;AdapterJS.WebRTCPlugin.pluginState!==AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY;);},AdapterJS.WebRTCPlugin.callWhenPluginReady=function(callback){if(AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY)callback();else var checkPluginReadyState=setInterval(function(){AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY&&(clearInterval(checkPluginReadyState),callback())},100)},AdapterJS.WebRTCPlugin.setLogLevel=function(logLevel){AdapterJS.WebRTCPlugin.callWhenPluginReady(function(){AdapterJS.WebRTCPlugin.plugin.setLogLevel(logLevel)})},AdapterJS.WebRTCPlugin.injectPlugin=function(){if("complete"===document.readyState&&AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING){if(AdapterJS.WebRTCPlugin.pluginState=AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTING,"IE"===webrtcDetectedBrowser&&webrtcDetectedVersion<=10){var frag=document.createDocumentFragment();for(AdapterJS.WebRTCPlugin.plugin=document.createElement("div"),AdapterJS.WebRTCPlugin.plugin.innerHTML=' '+(AdapterJS.options.getAllCams?'':"")+"";AdapterJS.WebRTCPlugin.plugin.firstChild;)frag.appendChild(AdapterJS.WebRTCPlugin.plugin.firstChild);document.body.appendChild(frag),AdapterJS.WebRTCPlugin.plugin=document.getElementById(AdapterJS.WebRTCPlugin.pluginInfo.pluginId)}else AdapterJS.WebRTCPlugin.plugin=document.createElement("object"),AdapterJS.WebRTCPlugin.plugin.id=AdapterJS.WebRTCPlugin.pluginInfo.pluginId,isIE?(AdapterJS.WebRTCPlugin.plugin.width="1px",AdapterJS.WebRTCPlugin.plugin.height="1px"):(AdapterJS.WebRTCPlugin.plugin.width="0px",AdapterJS.WebRTCPlugin.plugin.height="0px"),AdapterJS.WebRTCPlugin.plugin.type=AdapterJS.WebRTCPlugin.pluginInfo.type,AdapterJS.WebRTCPlugin.plugin.innerHTML=' '+(AdapterJS.options.getAllCams?'':"")+'',document.body.appendChild(AdapterJS.WebRTCPlugin.plugin);AdapterJS.WebRTCPlugin.pluginState=AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTED}},AdapterJS.WebRTCPlugin.isPluginInstalled=function(comName,plugName,plugType,installedCb,notInstalledCb){if(isIE){try{new ActiveXObject(comName+"."+plugName)}catch(e){return void notInstalledCb()}installedCb()}else{for(var pluginArray=navigator.mimeTypes,i=0;i=0)return void installedCb();notInstalledCb()}},AdapterJS.WebRTCPlugin.defineWebRTCInterface=function(){if(AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY)return void console.error("AdapterJS - WebRTC interface has already been defined");AdapterJS.WebRTCPlugin.pluginState=AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING,AdapterJS.isDefined=function(variable){return null!==variable&&void 0!==variable},createIceServer=function(url,username,password){var iceServer=null,urlParts=url.split(":");return 0===urlParts[0].indexOf("stun")?iceServer={url:url,hasCredentials:!1}:0===urlParts[0].indexOf("turn")&&(iceServer={url:url,hasCredentials:!0,credential:password,username:username}),iceServer},createIceServers=function(urls,username,password){for(var iceServers=[],i=0;i1)return iceServers&&(servers.iceServers=iceServers),AdapterJS.WebRTCPlugin.plugin.PeerConnection(servers);var mandatory=constraints&&constraints.mandatory?constraints.mandatory:null,optional=constraints&&constraints.optional?constraints.optional:null;return AdapterJS.WebRTCPlugin.plugin.PeerConnection(AdapterJS.WebRTCPlugin.pageId,iceServers,mandatory,optional)},MediaStreamTrack=function(){},MediaStreamTrack.getSources=function(callback){AdapterJS.WebRTCPlugin.callWhenPluginReady(function(){AdapterJS.WebRTCPlugin.plugin.GetSources(callback)})};var constraintsToPlugin=function(c){if("object"!=typeof c||c.mandatory||c.optional)return c;var cc={};return Object.keys(c).forEach(function(key){if("require"!==key&&"advanced"!==key){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,navigator.mediaDevices||"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(){isIE||navigator.plugins.refresh(!1),AdapterJS.WebRTCPlugin.isPluginInstalled(AdapterJS.WebRTCPlugin.pluginInfo.prefix,AdapterJS.WebRTCPlugin.pluginInfo.plugName,AdapterJS.WebRTCPlugin.pluginInfo.type,function(){clearInterval(pluginInstallInterval),AdapterJS.WebRTCPlugin.defineWebRTCInterface()},function(){})},500)})}else AdapterJS.renderNotificationBar(AdapterJS.TEXT.PLUGIN.NOT_SUPPORTED)}},AdapterJS.WebRTCPlugin.isPluginInstalled(AdapterJS.WebRTCPlugin.pluginInfo.prefix,AdapterJS.WebRTCPlugin.pluginInfo.plugName,AdapterJS.WebRTCPlugin.pluginInfo.type,AdapterJS.WebRTCPlugin.defineWebRTCInterface,AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCb)):(navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)&&window.RTCPeerConnection&&(window.msRTCPeerConnection=window.RTCPeerConnection),function(f){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=f();else if("function"==typeof define&&define.amd)define([],f);else{var g;g="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,g.adapter=f()}}(function(){return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n||e)},l,l.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o-1?(parts.attribute=line.substr(sp+1,colon-sp-1),parts.value=line.substr(colon+1)):parts.attribute=line.substr(sp+1),parts},SDPUtils.getMid=function(mediaSection){var mid=SDPUtils.matchPrefix(mediaSection,"a=mid:")[0];if(mid)return mid.substr(6)},SDPUtils.getDtlsParameters=function(mediaSection,sessionpart){var lines=SDPUtils.splitLines(mediaSection);lines=lines.concat(SDPUtils.splitLines(sessionpart));var fpLine=lines.filter(function(line){return 0===line.indexOf("a=fingerprint:")})[0].substr(14);return{role:"auto",fingerprints:[{algorithm:fpLine.split(" ")[0].toLowerCase(),value:fpLine.split(" ")[1]}]}},SDPUtils.writeDtlsParameters=function(params,setupType){var sdp="a=setup:"+setupType+"\r\n";return params.fingerprints.forEach(function(fp){sdp+="a=fingerprint:"+fp.algorithm+" "+fp.value+"\r\n"}),sdp},SDPUtils.getIceParameters=function(mediaSection,sessionpart){var lines=SDPUtils.splitLines(mediaSection);return lines=lines.concat(SDPUtils.splitLines(sessionpart)),{usernameFragment:lines.filter(function(line){return 0===line.indexOf("a=ice-ufrag:")})[0].substr(12),password:lines.filter(function(line){return 0===line.indexOf("a=ice-pwd:")})[0].substr(10)}},SDPUtils.writeIceParameters=function(params){return"a=ice-ufrag:"+params.usernameFragment+"\r\na=ice-pwd:"+params.password+"\r\n"},SDPUtils.parseRtpParameters=function(mediaSection){for(var description={codecs:[],headerExtensions:[],fecMechanisms:[],rtcp:[]},lines=SDPUtils.splitLines(mediaSection),mline=lines[0].split(" "),i=3;i0?"9":"0",sdp+=" UDP/TLS/RTP/SAVPF ",sdp+=caps.codecs.map(function(codec){return void 0!==codec.preferredPayloadType?codec.preferredPayloadType:codec.payloadType}).join(" ")+"\r\n",sdp+="c=IN IP4 0.0.0.0\r\n",sdp+="a=rtcp:9 IN IP4 0.0.0.0\r\n",caps.codecs.forEach(function(codec){sdp+=SDPUtils.writeRtpMap(codec),sdp+=SDPUtils.writeFmtp(codec),sdp+=SDPUtils.writeRtcpFb(codec)});var maxptime=0;return caps.codecs.forEach(function(codec){codec.maxptime>maxptime&&(maxptime=codec.maxptime)}),maxptime>0&&(sdp+="a=maxptime:"+maxptime+"\r\n"),sdp+="a=rtcp-mux\r\n",caps.headerExtensions.forEach(function(extension){sdp+=SDPUtils.writeExtmap(extension)}),sdp},SDPUtils.parseRtpEncodingParameters=function(mediaSection){var secondarySsrc,encodingParameters=[],description=SDPUtils.parseRtpParameters(mediaSection),hasRed=-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&&(0===bandwidth[0].indexOf("b=TIAS:")?bandwidth=parseInt(bandwidth[0].substr(7),10):0===bandwidth[0].indexOf("b=AS:")&&(bandwidth=parseInt(bandwidth[0].substr(5),10)),encodingParameters.forEach(function(params){params.maxBitrate=bandwidth})),encodingParameters},SDPUtils.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.writeSessionBoilerplate=function(){return"v=0\r\no=thisisadapterortc 8169639915646943137 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n"},SDPUtils.writeMediaSection=function(transceiver,caps,type,stream){var sdp=SDPUtils.writeRtpDescription(transceiver.kind,caps);if(sdp+=SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters()),sdp+=SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(),"offer"===type?"actpass":"active"),sdp+="a=mid:"+transceiver.mid+"\r\n",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(selector,successCallback);var fixChromeStats_=function(response){var standardReport={};return response.result().forEach(function(report){var standardStats={id:report.id,timestamp:report.timestamp,type:report.type};report.names().forEach(function(name){standardStats[name]=report.stat(name)}),standardReport[standardStats.id]=standardStats}),standardReport},makeMapStats=function(stats,legacyStats){var map=new Map(Object.keys(stats).map(function(key){return[key,stats[key]]}));return legacyStats=legacyStats||stats,Object.keys(legacyStats).forEach(function(key){map[key]=legacyStats[key]}),map};if(arguments.length>=2){var successCallbackWrapper_=function(response){args[1](makeMapStats(fixChromeStats_(response)))};return origGetStats.apply(this,[successCallbackWrapper_,arguments[0]])}return new Promise(function(resolve,reject){1===args.length&&"object"==typeof selector?origGetStats.apply(self,[function(response){resolve(makeMapStats(fixChromeStats_(response)))},reject]):origGetStats.apply(self,[function(response){resolve(makeMapStats(fixChromeStats_(response),response.result()))},reject])}).then(successCallback,errorCallback)},pc},window.RTCPeerConnection.prototype=webkitRTCPeerConnection.prototype,webkitRTCPeerConnection.generateCertificate&&Object.defineProperty(window.RTCPeerConnection,"generateCertificate",{get:function(){return webkitRTCPeerConnection.generateCertificate}}),["createOffer","createAnswer"].forEach(function(method){var nativeMethod=webkitRTCPeerConnection.prototype[method];webkitRTCPeerConnection.prototype[method]=function(){var self=this;if(arguments.length<1||1===arguments.length&&"object"==typeof arguments[0]){var opts=1===arguments.length?arguments[0]:void 0;return new Promise(function(resolve,reject){nativeMethod.apply(self,[resolve,reject,opts])})}return nativeMethod.apply(this,arguments)}}),browserDetails.version<51&&["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach(function(method){var nativeMethod=webkitRTCPeerConnection.prototype[method];webkitRTCPeerConnection.prototype[method]=function(){var args=arguments,self=this,promise=new Promise(function(resolve,reject){nativeMethod.apply(self,[args[0],resolve,reject])});return args.length<2?promise:promise.then(function(){args[1].apply(null,[])},function(err){args.length>=3&&args[2].apply(null,[err])})}}),["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach(function(method){var nativeMethod=webkitRTCPeerConnection.prototype[method];webkitRTCPeerConnection.prototype[method]=function(){return arguments[0]=new("addIceCandidate"===method?RTCIceCandidate:RTCSessionDescription)(arguments[0]),nativeMethod.apply(this,arguments)}});var nativeAddIceCandidate=RTCPeerConnection.prototype.addIceCandidate;RTCPeerConnection.prototype.addIceCandidate=function(){return null===arguments[0]?Promise.resolve():nativeAddIceCandidate.apply(this,arguments)}}};module.exports={shimMediaStream:chromeShim.shimMediaStream,shimOnTrack:chromeShim.shimOnTrack,shimSourceObject:chromeShim.shimSourceObject,shimPeerConnection:chromeShim.shimPeerConnection,shimGetUserMedia:requirecopy("./getusermedia")}},{"../utils.js":10,"./getusermedia":4}],4:[function(requirecopy,module,exports){"use strict";var logging=requirecopy("../utils.js").log;module.exports=function(){var constraintsToChrome_=function(c){if("object"!=typeof c||c.mandatory||c.optional)return c;var cc={};return Object.keys(c).forEach(function(key){if("require"!==key&&"advanced"!==key&&"mediaSource"!==key){var r="object"==typeof c[key]?c[key]:{ideal:c[key]};void 0!==r.exact&&"number"==typeof r.exact&&(r.min=r.max=r.exact);var oldname_=function(prefix,name){return prefix?prefix+name.charAt(0).toUpperCase()+name.slice(1):"deviceId"===name?"sourceId":name};if(void 0!==r.ideal){cc.optional=cc.optional||[];var oc={};"number"==typeof r.ideal?(oc[oldname_("min",key)]=r.ideal,cc.optional.push(oc),oc={},oc[oldname_("max",key)]=r.ideal,cc.optional.push(oc)):(oc[oldname_("",key)]=r.ideal,cc.optional.push(oc))}void 0!==r.exact&&"number"!=typeof r.exact?(cc.mandatory=cc.mandatory||{},cc.mandatory[oldname_("",key)]=r.exact):["min","max"].forEach(function(mix){void 0!==r[mix]&&(cc.mandatory=cc.mandatory||{},cc.mandatory[oldname_(mix,key)]=r[mix])})}}),c.advanced&&(cc.optional=(cc.optional||[]).concat(c.advanced)),cc},shimConstraints_=function(constraints,func){if(constraints=JSON.parse(JSON.stringify(constraints)),constraints&&constraints.audio&&(constraints.audio=constraintsToChrome_(constraints.audio)),constraints&&"object"==typeof constraints.video){var face=constraints.video.facingMode;if((face=face&&("object"==typeof face?face:{ideal:face}))&&("user"===face.exact||"environment"===face.exact||"user"===face.ideal||"environment"===face.ideal)&&(!navigator.mediaDevices.getSupportedConstraints||!navigator.mediaDevices.getSupportedConstraints().facingMode)&&(delete constraints.video.facingMode,"environment"===face.exact||"environment"===face.ideal))return navigator.mediaDevices.enumerateDevices().then(function(devices){devices=devices.filter(function(d){return"videoinput"===d.kind});var back=devices.find(function(d){return-1!==d.label.toLowerCase().indexOf("back")})||devices.length&&devices[devices.length-1];return back&&(constraints.video.deviceId=face.exact?{exact:back.deviceId}:{ideal:back.deviceId}),constraints.video=constraintsToChrome_(constraints.video),logging("chrome: "+JSON.stringify(constraints)),func(constraints)});constraints.video=constraintsToChrome_(constraints.video)}return logging("chrome: "+JSON.stringify(constraints)),func(constraints)},shimError_=function(e){return{name:{PermissionDeniedError:"NotAllowedError",ConstraintNotSatisfiedError:"OverconstrainedError"}[e.name]||e.name,message:e.message,constraint:e.constraintName,toString:function(){return this.name+(this.message&&": ")+this.message}}},getUserMedia_=function(constraints,onSuccess,onError){shimConstraints_(constraints,function(c){navigator.webkitGetUserMedia(c,onSuccess,function(e){onError(shimError_(e))})})};navigator.getUserMedia=getUserMedia_;var getUserMediaPromise_=function(constraints){return new Promise(function(resolve,reject){navigator.getUserMedia(constraints,resolve,reject)})};if(navigator.mediaDevices||(navigator.mediaDevices={getUserMedia:getUserMediaPromise_,enumerateDevices:function(){return new Promise(function(resolve){var kinds={audio:"audioinput",video:"videoinput"};return MediaStreamTrack.getSources(function(devices){resolve(devices.map(function(device){return{label:device.label,kind:kinds[device.kind],deviceId:device.id,groupId:""}}))})})}}),navigator.mediaDevices.getUserMedia){var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(cs){return shimConstraints_(cs,function(c){return origGetUserMedia(c).catch(function(e){return Promise.reject(shimError_(e))})})}}else navigator.mediaDevices.getUserMedia=function(constraints){return getUserMediaPromise_(constraints)};void 0===navigator.mediaDevices.addEventListener&&(navigator.mediaDevices.addEventListener=function(){logging("Dummy mediaDevices.addEventListener called.")}),void 0===navigator.mediaDevices.removeEventListener&&(navigator.mediaDevices.removeEventListener=function(){logging("Dummy mediaDevices.removeEventListener called.")})}},{"../utils.js":10}],5:[function(requirecopy,module,exports){"use strict";var SDPUtils=requirecopy("sdp"),browserDetails=requirecopy("../utils").browserDetails,edgeShim={shimPeerConnection:function(){window.RTCIceGatherer&&(window.RTCIceCandidate||(window.RTCIceCandidate=function(args){return args}),window.RTCSessionDescription||(window.RTCSessionDescription=function(args){return args})),window.RTCPeerConnection=function(config){var self=this,_eventTarget=document.createDocumentFragment();if(["addEventListener","removeEventListener","dispatchEvent"].forEach(function(method){self[method]=_eventTarget[method].bind(_eventTarget)}),this.onicecandidate=null,this.onaddstream=null,this.ontrack=null,this.onremovestream=null,this.onsignalingstatechange=null,this.oniceconnectionstatechange=null,this.onnegotiationneeded=null,this.ondatachannel=null,this.localStreams=[],this.remoteStreams=[],this.getLocalStreams=function(){return self.localStreams},this.getRemoteStreams=function(){return self.remoteStreams},this.localDescription=new RTCSessionDescription({type:"",sdp:""}),this.remoteDescription=new RTCSessionDescription({type:"",sdp:""}),this.signalingState="stable",this.iceConnectionState="new",this.iceGatheringState="new",this.iceOptions={gatherPolicy:"all",iceServers:[]},config&&config.iceTransportPolicy)switch(config.iceTransportPolicy){case"all":case"relay":this.iceOptions.gatherPolicy=config.iceTransportPolicy;break;case"none":throw new TypeError('iceTransportPolicy "none" not supported')}if(this.usingBundle=config&&"max-bundle"===config.bundlePolicy,config&&config.iceServers){var iceServers=JSON.parse(JSON.stringify(config.iceServers));this.iceOptions.iceServers=iceServers.filter(function(server){if(server&&server.urls){var urls=server.urls;return"string"==typeof urls&&(urls=[urls]),!!(urls=urls.filter(function(url){return 0===url.indexOf("turn:")&&-1!==url.indexOf("transport=udp")&&-1===url.indexOf("turn:[")||0===url.indexOf("stun:")&&browserDetails.version>=14393})[0])}return!1})}this.transceivers=[],this._localIceCandidatesBuffer=[]},window.RTCPeerConnection.prototype._emitBufferedCandidates=function(){var self=this,sections=SDPUtils.splitSections(self.localDescription.sdp);this._localIceCandidatesBuffer.forEach(function(event){if(event.candidate&&0!==Object.keys(event.candidate).length)-1===event.candidate.candidate.indexOf("typ endOfCandidates")&&(sections[event.candidate.sdpMLineIndex+1]+="a="+event.candidate.candidate+"\r\n");else for(var j=1;j-1&&(this.localStreams.splice(idx,1),this._maybeFireNegotiationNeeded())},window.RTCPeerConnection.prototype.getSenders=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpSender}).map(function(transceiver){return transceiver.rtpSender})},window.RTCPeerConnection.prototype.getReceivers=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpReceiver}).map(function(transceiver){return transceiver.rtpReceiver})},window.RTCPeerConnection.prototype._getCommonCapabilities=function(localCapabilities,remoteCapabilities){var commonCapabilities={codecs:[],headerExtensions:[],fecMechanisms:[]};return localCapabilities.codecs.forEach(function(lCodec){for(var i=0;i0;sections.forEach(function(mediaSection,sdpMLineIndex){var transceiver=self.transceivers[sdpMLineIndex],iceGatherer=transceiver.iceGatherer,iceTransport=transceiver.iceTransport,dtlsTransport=transceiver.dtlsTransport,localCapabilities=transceiver.localCapabilities,remoteCapabilities=transceiver.remoteCapabilities;if("0"!==mediaSection.split("\n",1)[0].split(" ",2)[1]&&!transceiver.isDatachannel){var remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);if(isIceLite){var cands=SDPUtils.matchPrefix(mediaSection,"a=candidate:").map(function(cand){return SDPUtils.parseCandidate(cand)}).filter(function(cand){return"1"===cand.component});cands.length&&iceTransport.setRemoteCandidates(cands)}var remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);isIceLite&&(remoteDtlsParameters.role="server"),self.usingBundle&&0!==sdpMLineIndex||(iceTransport.start(iceGatherer,remoteIceParameters,isIceLite?"controlling":"controlled"),dtlsTransport.start(remoteDtlsParameters));var params=self._getCommonCapabilities(localCapabilities,remoteCapabilities);self._transceive(transceiver,params.codecs.length>0,!1)}})}switch(this.localDescription={type:description.type,sdp:description.sdp},description.type){case"offer":this._updateSignalingState("have-local-offer");break;case"answer":this._updateSignalingState("stable");break;default:throw new TypeError('unsupported type "'+description.type+'"')}var hasCallback=arguments.length>1&&"function"==typeof arguments[1];if(hasCallback){var cb=arguments[1];window.setTimeout(function(){cb(),"new"===self.iceGatheringState&&(self.iceGatheringState="gathering"),self._emitBufferedCandidates()},0)}var p=Promise.resolve();return p.then(function(){hasCallback||("new"===self.iceGatheringState&&(self.iceGatheringState="gathering"),window.setTimeout(self._emitBufferedCandidates.bind(self),500))}),p},window.RTCPeerConnection.prototype.setRemoteDescription=function(description){var self=this,stream=new MediaStream,receiverList=[],sections=SDPUtils.splitSections(description.sdp),sessionpart=sections.shift(),isIceLite=SDPUtils.matchPrefix(sessionpart,"a=ice-lite").length>0;switch(this.usingBundle=SDPUtils.matchPrefix(sessionpart,"a=group:BUNDLE ").length>0,sections.forEach(function(mediaSection,sdpMLineIndex){var lines=SDPUtils.splitLines(mediaSection),mline=lines[0].substr(2).split(" "),kind=mline[0],rejected="0"===mline[1],direction=SDPUtils.getDirection(mediaSection,sessionpart),mid=SDPUtils.matchPrefix(mediaSection,"a=mid:");if(mid=mid.length?mid[0].substr(6):SDPUtils.generateIdentifier(),"application"===kind&&"DTLS/SCTP"===mline[2])return void(self.transceivers[sdpMLineIndex]={mid:mid,isDatachannel:!0});var transceiver,iceGatherer,iceTransport,dtlsTransport,rtpSender,rtpReceiver,sendEncodingParameters,recvEncodingParameters,localCapabilities,track,remoteIceParameters,remoteDtlsParameters,remoteCapabilities=SDPUtils.parseRtpParameters(mediaSection);rejected||(remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart),remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart),remoteDtlsParameters.role="client"),recvEncodingParameters=SDPUtils.parseRtpEncodingParameters(mediaSection);var cname,remoteSsrc=SDPUtils.matchPrefix(mediaSection,"a=ssrc:").map(function(line){return SDPUtils.parseSsrcMedia(line)}).filter(function(obj){return"cname"===obj.attribute})[0];remoteSsrc&&(cname=remoteSsrc.value);var isComplete=SDPUtils.matchPrefix(mediaSection,"a=end-of-candidates",sessionpart).length>0,cands=SDPUtils.matchPrefix(mediaSection,"a=candidate:").map(function(cand){return SDPUtils.parseCandidate(cand)}).filter(function(cand){return"1"===cand.component});if("offer"!==description.type||rejected)"answer"!==description.type||rejected||(transceiver=self.transceivers[sdpMLineIndex],iceGatherer=transceiver.iceGatherer,iceTransport=transceiver.iceTransport,dtlsTransport=transceiver.dtlsTransport,rtpSender=transceiver.rtpSender,rtpReceiver=transceiver.rtpReceiver,sendEncodingParameters=transceiver.sendEncodingParameters,localCapabilities=transceiver.localCapabilities,self.transceivers[sdpMLineIndex].recvEncodingParameters=recvEncodingParameters,self.transceivers[sdpMLineIndex].remoteCapabilities=remoteCapabilities,self.transceivers[sdpMLineIndex].cname=cname,(isIceLite||isComplete)&&cands.length&&iceTransport.setRemoteCandidates(cands),self.usingBundle&&0!==sdpMLineIndex||(iceTransport.start(iceGatherer,remoteIceParameters,"controlling"),dtlsTransport.start(remoteDtlsParameters)),self._transceive(transceiver,"sendrecv"===direction||"recvonly"===direction,"sendrecv"===direction||"sendonly"===direction),!rtpReceiver||"sendrecv"!==direction&&"sendonly"!==direction?delete transceiver.rtpReceiver:(track=rtpReceiver.track,receiverList.push([track,rtpReceiver]),stream.addTrack(track)));else{var transports=self.usingBundle&&sdpMLineIndex>0?{iceGatherer:self.transceivers[0].iceGatherer,iceTransport:self.transceivers[0].iceTransport,dtlsTransport:self.transceivers[0].dtlsTransport}:self._createIceAndDtlsTransports(mid,sdpMLineIndex);if(isComplete&&transports.iceTransport.setRemoteCandidates(cands),localCapabilities=RTCRtpReceiver.getCapabilities(kind),sendEncodingParameters=[{ssrc:1001*(2*sdpMLineIndex+2)}],rtpReceiver=new RTCRtpReceiver(transports.dtlsTransport,kind),track=rtpReceiver.track,receiverList.push([track,rtpReceiver]),stream.addTrack(track),self.localStreams.length>0&&self.localStreams[0].getTracks().length>=sdpMLineIndex){var localTrack;"audio"===kind?localTrack=self.localStreams[0].getAudioTracks()[0]:"video"===kind&&(localTrack=self.localStreams[0].getVideoTracks()[0]),localTrack&&(rtpSender=new RTCRtpSender(localTrack,transports.dtlsTransport))}self.transceivers[sdpMLineIndex]={iceGatherer:transports.iceGatherer,iceTransport:transports.iceTransport,dtlsTransport:transports.dtlsTransport,localCapabilities:localCapabilities,remoteCapabilities:remoteCapabilities,rtpSender:rtpSender,rtpReceiver:rtpReceiver,kind:kind,mid:mid,cname:cname,sendEncodingParameters:sendEncodingParameters,recvEncodingParameters:recvEncodingParameters},self._transceive(self.transceivers[sdpMLineIndex],!1,"sendrecv"===direction||"sendonly"===direction)}}),this.remoteDescription={type:description.type,sdp:description.sdp},description.type){case"offer":this._updateSignalingState("have-remote-offer");break;case"answer":this._updateSignalingState("stable");break;default:throw new TypeError('unsupported type "'+description.type+'"')}return stream.getTracks().length&&(self.remoteStreams.push(stream),window.setTimeout(function(){var event=new Event("addstream");event.stream=stream,self.dispatchEvent(event),null!==self.onaddstream&&window.setTimeout(function(){self.onaddstream(event)},0),receiverList.forEach(function(item){var track=item[0],receiver=item[1],trackEvent=new Event("track");trackEvent.track=track,trackEvent.receiver=receiver,trackEvent.streams=[stream],self.dispatchEvent(event),null!==self.ontrack&&window.setTimeout(function(){self.ontrack(trackEvent)},0)})},0)),arguments.length>1&&"function"==typeof arguments[1]&&window.setTimeout(arguments[1],0),Promise.resolve()},window.RTCPeerConnection.prototype.close=function(){this.transceivers.forEach(function(transceiver){transceiver.iceTransport&&transceiver.iceTransport.stop(),transceiver.dtlsTransport&&transceiver.dtlsTransport.stop(),transceiver.rtpSender&&transceiver.rtpSender.stop(),transceiver.rtpReceiver&&transceiver.rtpReceiver.stop()}),this._updateSignalingState("closed")},window.RTCPeerConnection.prototype._updateSignalingState=function(newState){this.signalingState=newState;var event=new Event("signalingstatechange");this.dispatchEvent(event),null!==this.onsignalingstatechange&&this.onsignalingstatechange(event)},window.RTCPeerConnection.prototype._maybeFireNegotiationNeeded=function(){var event=new Event("negotiationneeded");this.dispatchEvent(event),null!==this.onnegotiationneeded&&this.onnegotiationneeded(event)},window.RTCPeerConnection.prototype._updateConnectionState=function(){var newState,self=this,states={new:0,closed:0,connecting:0,checking:0,connected:0,completed:0,failed:0};if(this.transceivers.forEach(function(transceiver){states[transceiver.iceTransport.state]++,states[transceiver.dtlsTransport.state]++}),states.connected+=states.completed,newState="new",states.failed>0?newState="failed":states.connecting>0||states.checking>0?newState="connecting":states.disconnected>0?newState="disconnected":states.new>0?newState="new":(states.connected>0||states.completed>0)&&(newState="connected"),newState!==self.iceConnectionState){self.iceConnectionState=newState;var event=new Event("iceconnectionstatechange");this.dispatchEvent(event),null!==this.oniceconnectionstatechange&&this.oniceconnectionstatechange(event)}},window.RTCPeerConnection.prototype.createOffer=function(){var self=this;if(this._pendingOffer)throw new Error("createOffer called while there is a pending offer.");var offerOptions;1===arguments.length&&"function"!=typeof arguments[0]?offerOptions=arguments[0]:3===arguments.length&&(offerOptions=arguments[2]) -;var tracks=[],numAudioTracks=0,numVideoTracks=0;if(this.localStreams.length&&(numAudioTracks=this.localStreams[0].getAudioTracks().length,numVideoTracks=this.localStreams[0].getVideoTracks().length),offerOptions){if(offerOptions.mandatory||offerOptions.optional)throw new TypeError("Legacy mandatory/optional constraints not supported.");void 0!==offerOptions.offerToReceiveAudio&&(numAudioTracks=offerOptions.offerToReceiveAudio),void 0!==offerOptions.offerToReceiveVideo&&(numVideoTracks=offerOptions.offerToReceiveVideo)}for(this.localStreams.length&&this.localStreams[0].getTracks().forEach(function(track){tracks.push({kind:track.kind,track:track,wantReceive:"audio"===track.kind?numAudioTracks>0:numVideoTracks>0}),"audio"===track.kind?numAudioTracks--:"video"===track.kind&&numVideoTracks--});numAudioTracks>0||numVideoTracks>0;)numAudioTracks>0&&(tracks.push({kind:"audio",wantReceive:!0}),numAudioTracks--),numVideoTracks>0&&(tracks.push({kind:"video",wantReceive:!0}),numVideoTracks--);var sdp=SDPUtils.writeSessionBoilerplate(),transceivers=[];tracks.forEach(function(mline,sdpMLineIndex){var rtpSender,rtpReceiver,track=mline.track,kind=mline.kind,mid=SDPUtils.generateIdentifier(),transports=self.usingBundle&&sdpMLineIndex>0?{iceGatherer:transceivers[0].iceGatherer,iceTransport:transceivers[0].iceTransport,dtlsTransport:transceivers[0].dtlsTransport}:self._createIceAndDtlsTransports(mid,sdpMLineIndex),localCapabilities=RTCRtpSender.getCapabilities(kind),sendEncodingParameters=[{ssrc:1001*(2*sdpMLineIndex+1)}];track&&(rtpSender=new RTCRtpSender(track,transports.dtlsTransport)),mline.wantReceive&&(rtpReceiver=new RTCRtpReceiver(transports.dtlsTransport,kind)),transceivers[sdpMLineIndex]={iceGatherer:transports.iceGatherer,iceTransport:transports.iceTransport,dtlsTransport:transports.dtlsTransport,localCapabilities:localCapabilities,remoteCapabilities:null,rtpSender:rtpSender,rtpReceiver:rtpReceiver,kind:kind,mid:mid,sendEncodingParameters:sendEncodingParameters,recvEncodingParameters:null}}),this.usingBundle&&(sdp+="a=group:BUNDLE "+transceivers.map(function(t){return t.mid}).join(" ")+"\r\n"),tracks.forEach(function(mline,sdpMLineIndex){var transceiver=transceivers[sdpMLineIndex];sdp+=SDPUtils.writeMediaSection(transceiver,transceiver.localCapabilities,"offer",self.localStreams[0])}),this._pendingOffer=transceivers;var desc=new RTCSessionDescription({type:"offer",sdp:sdp});return arguments.length&&"function"==typeof arguments[0]&&window.setTimeout(arguments[0],0,desc),Promise.resolve(desc)},window.RTCPeerConnection.prototype.createAnswer=function(){var self=this,sdp=SDPUtils.writeSessionBoilerplate();this.usingBundle&&(sdp+="a=group:BUNDLE "+this.transceivers.map(function(t){return t.mid}).join(" ")+"\r\n"),this.transceivers.forEach(function(transceiver){if(transceiver.isDatachannel)return void(sdp+="m=application 0 DTLS/SCTP 5000\r\nc=IN IP4 0.0.0.0\r\na=mid:"+transceiver.mid+"\r\n");var commonCapabilities=self._getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);sdp+=SDPUtils.writeMediaSection(transceiver,commonCapabilities,"answer",self.localStreams[0])});var desc=new RTCSessionDescription({type:"answer",sdp:sdp});return arguments.length&&"function"==typeof arguments[0]&&window.setTimeout(arguments[0],0,desc),Promise.resolve(desc)},window.RTCPeerConnection.prototype.addIceCandidate=function(candidate){if(null===candidate)this.transceivers.forEach(function(transceiver){transceiver.iceTransport.addRemoteCandidate({})});else{var mLineIndex=candidate.sdpMLineIndex;if(candidate.sdpMid)for(var i=0;i0?SDPUtils.parseCandidate(candidate.candidate):{};if("tcp"===cand.protocol&&(0===cand.port||9===cand.port))return;if("1"!==cand.component)return;"endOfCandidates"===cand.type&&(cand={}),transceiver.iceTransport.addRemoteCandidate(cand);var sections=SDPUtils.splitSections(this.remoteDescription.sdp);sections[mLineIndex+1]+=(cand.type?candidate.candidate.trim():"a=end-of-candidates")+"\r\n",this.remoteDescription.sdp=sections.join("")}}return arguments.length>1&&"function"==typeof arguments[1]&&window.setTimeout(arguments[1],0),Promise.resolve()},window.RTCPeerConnection.prototype.getStats=function(){var promises=[];this.transceivers.forEach(function(transceiver){["rtpSender","rtpReceiver","iceGatherer","iceTransport","dtlsTransport"].forEach(function(method){transceiver[method]&&promises.push(transceiver[method].getStats())})});var cb=arguments.length>1&&"function"==typeof arguments[1]&&arguments[1];return new Promise(function(resolve){var results=new Map;Promise.all(promises).then(function(res){res.forEach(function(result){Object.keys(result).forEach(function(id){results.set(id,result[id]),results[id]=result[id]})}),cb&&window.setTimeout(cb,0,results),resolve(results)})})}}};module.exports={shimPeerConnection:edgeShim.shimPeerConnection,shimGetUserMedia:requirecopy("./getusermedia")}},{"../utils":10,"./getusermedia":6,sdp:1}],6:[function(requirecopy,module,exports){"use strict";module.exports=function(){var shimError_=function(e){return{name:{PermissionDeniedError:"NotAllowedError"}[e.name]||e.name,message:e.message,constraint:e.constraint,toString:function(){return this.name}}},origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(c){return origGetUserMedia(c).catch(function(e){return Promise.reject(shimError_(e))})}}},{}],7:[function(requirecopy,module,exports){"use strict";var browserDetails=requirecopy("../utils").browserDetails,firefoxShim={shimOnTrack:function(){"object"!=typeof window||!window.RTCPeerConnection||"ontrack"in window.RTCPeerConnection.prototype||Object.defineProperty(window.RTCPeerConnection.prototype,"ontrack",{get:function(){return this._ontrack},set:function(f){this._ontrack&&(this.removeEventListener("track",this._ontrack),this.removeEventListener("addstream",this._ontrackpoly)),this.addEventListener("track",this._ontrack=f),this.addEventListener("addstream",this._ontrackpoly=function(e){e.stream.getTracks().forEach(function(track){var event=new Event("track");event.track=track,event.receiver={track:track},event.streams=[e.stream],this.dispatchEvent(event)}.bind(this))}.bind(this))}})},shimSourceObject:function(){"object"==typeof window&&(!window.HTMLMediaElement||"srcObject"in window.HTMLMediaElement.prototype||Object.defineProperty(window.HTMLMediaElement.prototype,"srcObject",{get:function(){return this.mozSrcObject},set:function(stream){this.mozSrcObject=stream}}))},shimPeerConnection:function(){if("object"==typeof window&&(window.RTCPeerConnection||window.mozRTCPeerConnection)){window.RTCPeerConnection||(window.RTCPeerConnection=function(pcConfig,pcConstraints){if(browserDetails.version<38&&pcConfig&&pcConfig.iceServers){for(var newIceServers=[],i=0;i=pos&&parseInt(match[pos],10)},detectBrowser:function(){var result={};if(result.browser=null,result.version=null,"undefined"==typeof window||!window.navigator)return result.browser="Not a browser.",result;if(navigator.mozGetUserMedia)result.browser="firefox",result.version=this.extractVersion(navigator.userAgent,/Firefox\/([0-9]+)\./,1);else if(navigator.webkitGetUserMedia)if(window.webkitRTCPeerConnection)result.browser="chrome",result.version=this.extractVersion(navigator.userAgent,/Chrom(e|ium)\/([0-9]+)\./,2);else{if(!navigator.userAgent.match(/Version\/(\d+).(\d+)/))return result.browser="Unsupported webkit-based browser with GUM support but no WebRTC support.",result;result.browser="safari",result.version=this.extractVersion(navigator.userAgent,/AppleWebKit\/([0-9]+)\./,1)}else{if(!navigator.mediaDevices||!navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))return result.browser="Not a supported browser.",result;result.browser="edge",result.version=this.extractVersion(navigator.userAgent,/Edge\/(\d+).(\d+)$/,2)}return result}};module.exports={log:utils.log,disableLog:utils.disableLog,browserDetails:utils.detectBrowser(),extractVersion:utils.extractVersion}},{}]},{},[2])(2)}),AdapterJS.parseWebrtcDetectedBrowser(),navigator.mozGetUserMedia?(MediaStreamTrack.getSources=function(successCb){setTimeout(function(){successCb([{kind:"audio",id:"default",label:"",facing:""},{kind:"video",id:"default",label:"",facing:""}])},0)},attachMediaStream=function(element,stream){return element.srcObject=stream,element},reattachMediaStream=function(to,from){return to.srcObject=from.srcObject,to},createIceServer=function(url,username,password){console.warn("createIceServer is deprecated. It should be replaced with an application level implementation.");var iceServer=null,urlParts=url.split(":");if(0===urlParts[0].indexOf("stun"))iceServer={urls:[url]};else if(0===urlParts[0].indexOf("turn"))if(webrtcDetectedVersion<27){var turnUrlParts=url.split("?");1!==turnUrlParts.length&&0!==turnUrlParts[1].indexOf("transport=udp")||(iceServer={urls:[turnUrlParts[0]],credential:password,username:username})}else iceServer={urls:[url],credential:password,username:username};return iceServer},createIceServers=function(urls,username,password){console.warn("createIceServers is deprecated. It should be replaced with an application level implementation.");var iceServers=[];for(i=0;i=43?element.srcObject=stream:void 0!==element.src?element.src=URL.createObjectURL(stream):console.error("Error attaching stream to element."),element},reattachMediaStream=function(to,from){return webrtcDetectedVersion>=43?to.srcObject=from.srcObject:to.src=from.src,to},createIceServer=function(url,username,password){console.warn("createIceServer is deprecated. It should be replaced with an application level implementation.");var iceServer=null,urlParts=url.split(":");return 0===urlParts[0].indexOf("stun")?iceServer={url:url}:0===urlParts[0].indexOf("turn")&&(iceServer={url:url,credential:password,username:username}),iceServer},createIceServers=function(urls,username,password){console.warn("createIceServers is deprecated. It should be replaced with an application level implementation.");var iceServers=[];if(webrtcDetectedVersion>=34)iceServers={urls:urls,credential:password,username:username};else for(i=0;i38?element.srcObject=stream:void 0!==element.src&&(element.src=URL.createObjectURL(stream))}),attachMediaStream=function(element,stream){return"chrome"!==webrtcDetectedBrowser&&"opera"!==webrtcDetectedBrowser||stream?attachMediaStream_base(element,stream):element.src="",element},reattachMediaStream_base=reattachMediaStream,reattachMediaStream=function(to,from){return reattachMediaStream_base(to,from),to},window.attachMediaStream=attachMediaStream,window.reattachMediaStream=reattachMediaStream,window.getUserMedia=function(constraints,onSuccess,onFailure){navigator.getUserMedia(constraints,onSuccess,onFailure)},AdapterJS.attachMediaStream=attachMediaStream,AdapterJS.reattachMediaStream=reattachMediaStream,AdapterJS.getUserMedia=getUserMedia,"undefined"==typeof Promise&&(requestUserMedia=null),AdapterJS.maybeThroughWebRTCReady()),"undefined"!=typeof exports&&(module.exports=AdapterJS),AdapterJS.TEXT.EXTENSION={REQUIRE_INSTALLATION_FF:"To enable screensharing you need to install the Skylink WebRTC tools Firefox Add-on.",REQUIRE_INSTALLATION_CHROME:"To enable screensharing you need to install the Skylink WebRTC tools Chrome Extension.",REQUIRE_REFRESH:"Please refresh this page after the Skylink WebRTC tools extension has been installed.",BUTTON_FF:"Install Now",BUTTON_CHROME:"Go to Chrome Web Store"},AdapterJS.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(window.navigator.mozGetUserMedia)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&&window.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(window.navigator.webkitGetUserMedia&&"safari"!==window.webrtcDetectedBrowser){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"===window.webrtcDetectedBrowser?!!AdapterJS.extensionInfo.opera.extensionId:"chrome"===window.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"!==window.webrtcDetectedBrowser)iframe.getSourceId(updatedConstraints.video.mediaSource,fetchStream);else{var extensionId=AdapterJS.extensionInfo["opera"===window.webrtcDetectedBrowser?"opera":"chrome"].extensionId,extensionLink=AdapterJS.extensionInfo["opera"===window.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"===window.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 navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)?console.warn("Edge does not support screensharing feature in getUserMedia"):(baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(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._isUsingPlugin=!1,this._TURNTransport="any",this._peerInformations={},this._user=null,this._userData="",this._peerPriorityWeight=0,this._autoIntroduce=!0,this._isPrivileged=!1,this._peerList=null,this._selectedRoom=null,this._roomLocked=!1,this._inRoom=!1,this._EVENTS={},this._onceEvents={},this._timestamp={socketMessage:null,shareScreen:null,refreshConnection:null,getUserMedia:null,lastRestart:null},this._throttlingTimeouts={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},this._throttlingShouldThrowError=!1,this._socketSession={},this._socketMessageQueue=[],this._socketMessageTimeout=null,this._socketPorts={"http:":[80,3e3],"https:":[443,3443]},this._channelOpen=!1,this._signalingServer=null,this._signalingServerProtocol=window.location.protocol,this._signalingServerPort=null,this._socket=null,this._socketTimeout=2e4,this._socketUseXDR=!1,this._enableIceRestart="firefox"!==window.webrtcDetectedBrowser||window.webrtcDetectedVersion>=48,this._hasMCU=!1,this._forceSSL=!1,this._forceTURNSSL=!1,this._forceTURN=!1,this._path=null,this._roomServer="//api.temasys.io",this._appKey=null,this._defaultRoom=null,this._roomStart=null,this._roomDuration=null,this._roomCredentials=null,this._readyState=0,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._audioFallback=!1,this._streams={userMedia:null,screenshare:null},this._streamsDefaultSettings={userMedia:{audio:{stereo:!1},video:{resolution:{width:640,height:480},frameRate:50}},screenshare:{video:!0}},this._streamsMutedSettings={audioMuted:!1,videoMuted:!1},this._streamsBandwidthSettings={googleX:{},bAS:{}},this._streamsStoppedCbs={},this._streamsSession={},this._selectedAudioCodec="auto",this._selectedVideoCodec="auto",this._disableVideoFecCodecs=!1,this._disableComfortNoiseCodec=!1,this._disableREMB=!1,this._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},this._publishOnly=!1,this._parentId=null,this._recordings={},this._currentRecordingId=!1,this._recordingStartInterval=null,this._mcuUseRenegoRestart=!1,this._iceServer=null,this._socketServer=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType="firefox"===window.webrtcDetectedBrowser?this.DATA_TRANSFER_DATA_TYPE.BLOB:this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={},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;var clone=function(obj){if(null===obj||"object"!=typeof obj)return obj;var copy=function(data){var copy=data.constructor();for(var attr in data)data.hasOwnProperty(attr)&&(copy[attr]=data[attr]);return copy};if("object"==typeof obj&&!Array.isArray(obj))try{return JSON.parse(JSON.stringify(obj))}catch(err){return copy(obj)}return copy(obj)};Skylink.prototype.DATA_CHANNEL_STATE={CONNECTING:"connecting",OPEN:"open",CLOSING:"closing",CLOSED:"closed",ERROR:"error",CREATE_ERROR:"createError",BUFFERED_AMOUNT_LOW:"bufferedAmountLow",SEND_MESSAGE_ERROR:"sendMessageError"},Skylink.prototype.DATA_CHANNEL_TYPE={MESSAGING:"messaging",DATA:"data"},Skylink.prototype.DATA_CHANNEL_MESSAGE_ERROR={MESSAGE:"message",TRANSFER:"transfer"},Skylink.prototype._createDataChannel=function(peerId,dataChannel,bufferThreshold,createAsMessagingChannel){var self=this,channelName=(self._user&&self._user.sid?self._user.sid:"-")+"_"+peerId,channelType=createAsMessagingChannel?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,channelProp=channelType===self.DATA_CHANNEL_TYPE.MESSAGING?"main":channelName;if(!self._user)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as User does not have Room session"]);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as Peer connection does not exists"]);if(dataChannel&&"object"==typeof dataChannel?channelName=dataChannel.label:"string"==typeof dataChannel&&(channelName=dataChannel,dataChannel=null),!dataChannel)try{dataChannel=self._peerConnections[peerId].createDataChannel(channelName,{reliable:!0,ordered:!0})}catch(error){return log.error([peerId,"RTCDataChannel",channelProp,"Failed creating Datachannel ->"],error),void self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CREATE_ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))}self._dataChannels[peerId]?self._dataChannels[peerId].main&&self._dataChannels[peerId].main.channel.label===channelName&&(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING):(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING,self._dataChannels[peerId]={},log.debug([peerId,"RTCDataChannel",channelProp,"initializing main DataChannel"])),dataChannel.onerror=function(evt){var channelError=evt.error||evt;log.error([peerId,"RTCDataChannel",channelProp,"Datachannel has an exception ->"],channelError),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,channelError,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onbufferedamountlow=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel buffering data transfer low"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.BUFFERED_AMOUNT_LOW,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onmessage=function(event){self._processDataChannelData(event.data,peerId,channelName,channelType)};var onOpenHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has opened"]),dataChannel.bufferedAmountLowThreshold=bufferThreshold||0,self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.OPEN,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))};dataChannel.readyState===self.DATA_CHANNEL_STATE.OPEN?setTimeout(onOpenHandlerFn,1):(self._trigger("dataChannelState",dataChannel.readyState,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),dataChannel.onopen=onOpenHandlerFn);var onCloseHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has closed"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSED,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),self._peerConnections[peerId]&&self._peerConnections[peerId].remoteDescription&&self._peerConnections[peerId].remoteDescription.sdp&&(-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"===window.webrtcDetectedBrowser){var hasTriggeredClose=!1,timeBlockAfterClosing=0;dataChannel.onclose=function(){hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())};var onFFClosed=setInterval(function(){dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSED||hasTriggeredClose||5===timeBlockAfterClosing?(clearInterval(onFFClosed),hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())):dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSING&&timeBlockAfterClosing++},1e3)}else dataChannel.onclose=onCloseHandlerFn;channelType===self.DATA_CHANNEL_TYPE.MESSAGING?self._dataChannels[peerId].main={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}:self._dataChannels[peerId][channelName]={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}},Skylink.prototype._getDataChannelBuffer=function(peerId,channelProp){if("object"==typeof peerId)return{bufferedAmountLow:"number"==typeof peerId.bufferedAmountLow?peerId.bufferedAmountLow:parseInt(peerId.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof peerId.bufferedAmountLowThreshold?peerId.bufferedAmountLowThreshold:parseInt(peerId.bufferedAmountLowThreshold,10)||0};if(!(this._dataChannels[peerId]&&this._dataChannels[peerId][channelProp]&&this._dataChannels[peerId][channelProp].channel))return{bufferedAmountLow:0,bufferedAmountLowThreshold:0};var channel=this._dataChannels[peerId][channelProp].channel;return{bufferedAmountLow:"number"==typeof channel.bufferedAmountLow?channel.bufferedAmountLow:parseInt(channel.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof channel.bufferedAmountLowThreshold?channel.bufferedAmountLowThreshold:parseInt(channel.bufferedAmountLowThreshold,10)||0}},Skylink.prototype._sendMessageToDataChannel=function(peerId,data,channelProp,doNotConvert){var self=this;if(channelProp&&channelProp!==peerId||(channelProp="main"),!("object"==typeof data&&data||data&&"string"==typeof data))return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping invalid data ->"],data);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Peer connection does not exists or is closed ->"],data);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Datachannel connection does not exists ->"],data);var channelName=self._dataChannels[peerId][channelProp].channelName,channelType=self._dataChannels[peerId][channelProp].channelType,readyState=self._dataChannels[peerId][channelProp].channel.readyState,messageType="object"==typeof data&&data.type===self._DC_PROTOCOL_TYPE.MESSAGE?self.DATA_CHANNEL_MESSAGE_ERROR.MESSAGE:self.DATA_CHANNEL_MESSAGE_ERROR.TRANSFER;if(readyState!==self.DATA_CHANNEL_STATE.OPEN){var notOpenError='Failed sending message as Datachannel connection state is not opened. Current readyState is "'+readyState+'"';throw log.error([peerId,"RTCDataChannel",channelProp,notOpenError+" ->"],data),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,new Error(notOpenError),channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),new Error(notOpenError)}try{doNotConvert||"object"!=typeof data?(log.debug([peerId,"RTCDataChannel",channelProp,"Sending data with size ->"],data.size||data.length||data.byteLength),self._dataChannels[peerId][channelProp].channel.send(data)):(log.debug([peerId,"RTCDataChannel",channelProp,'Sending "'+data.type+'" protocol message ->'],data),self._dataChannels[peerId][channelProp].channel.send(JSON.stringify(data)))}catch(error){throw log.error([peerId,"RTCDataChannel",channelProp,"Failed sending "+(doNotConvert||"object"!=typeof data?"data":'"'+data.type+'" protocol message')+" ->"],error),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,error,channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),error}},Skylink.prototype._closeDataChannel=function(peerId,channelProp){var self=this;if(!self._dataChannels[peerId])return void log.warn([peerId,"RTCDataChannel",channelProp||null,"Aborting closing Datachannels as Peer connection does not have Datachannel sessions"]);var closeFn=function(rChannelProp){var channelName=self._dataChannels[peerId][rChannelProp].channelName,channelType=self._dataChannels[peerId][rChannelProp].channelType;self._dataChannels[peerId][rChannelProp].readyState!==self.DATA_CHANNEL_STATE.CLOSED&&(log.debug([peerId,"RTCDataChannel",channelProp,"Closing Datachannel"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSING,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(peerId,rChannelProp)),self._dataChannels[peerId][rChannelProp].channel.close(),delete self._dataChannels[peerId][rChannelProp])};if(channelProp){if(!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Aborting closing Datachannel as it does not exists"]);closeFn(channelProp)}else for(var channelNameProp in self._dataChannels)self._dataChannels[peerId].hasOwnProperty(channelNameProp)&&self._dataChannels[peerId][channelNameProp]&&closeFn(channelNameProp)},Skylink.prototype.DATA_TRANSFER_DATA_TYPE={BINARY_STRING:"binaryString",ARRAY_BUFFER:"arrayBuffer",BLOB:"blob",STRING:"string"},Skylink.prototype._CHUNK_FILE_SIZE=49152,Skylink.prototype._MOZ_CHUNK_FILE_SIZE=12288,Skylink.prototype._BINARY_FILE_SIZE=65456,Skylink.prototype._MOZ_BINARY_FILE_SIZE=16384,Skylink.prototype._CHUNK_DATAURL_SIZE=1212,Skylink.prototype._base64ToBlob=function(dataURL){for(var byteString=atob(dataURL),ab=new ArrayBuffer(byteString.length),ia=new Uint8Array(ab),j=0;jchunkSize){for(;blobByteSize-1>endCount;)endCount=startCount+chunkSize,chunksArray.push(blob.slice(startCount,endCount)),startCount+=chunkSize;blobByteSize-(startCount+1)>0&&chunksArray.push(blob.slice(startCount,blobByteSize-1))}else chunksArray.push(blob);return chunksArray},Skylink.prototype._chunkDataURL=function(dataURL,chunkSize){var outputStr=dataURL,dataURLArray=[],startCount=0,endCount=0,dataByteSize=dataURL.size||dataURL.length;if(dataByteSize>chunkSize){for(;dataByteSize-1>endCount;)endCount=startCount+chunkSize,dataURLArray.push(outputStr.slice(startCount,endCount)),startCount+=chunkSize;dataByteSize-(startCount+1)>0&&chunksArray.push(outputStr.slice(startCount,dataByteSize-1))}else dataURLArray.push(outputStr);return dataURLArray},Skylink.prototype.DT_PROTOCOL_VERSION="0.1.3",Skylink.prototype.DATA_TRANSFER_TYPE={UPLOAD:"upload",DOWNLOAD:"download"},Skylink.prototype.DATA_TRANSFER_SESSION_TYPE={BLOB:"blob",DATA_URL:"dataURL"},Skylink.prototype.DATA_TRANSFER_STATE={UPLOAD_REQUEST:"request",UPLOAD_STARTED:"uploadStarted",DOWNLOAD_STARTED:"downloadStarted",REJECTED:"rejected",CANCEL:"cancel",ERROR:"error",UPLOADING:"uploading",DOWNLOADING:"downloading",UPLOAD_COMPLETED:"uploadCompleted",DOWNLOAD_COMPLETED:"downloadCompleted",USER_REJECTED:"userRejected",USER_UPLOAD_REQUEST:"userRequest",START_ERROR:"startError"},Skylink.prototype.DATA_STREAM_STATE={SENDING_STARTED:"sendStart",SENDING_STOPPED:"sendStop",RECEIVING_STARTED:"receiveStart",RECEIVING_STOPPED:"receiveStop",RECEIVED:"received",SENT:"sent",ERROR:"error",START_ERROR:"startError"},Skylink.prototype._DC_PROTOCOL_TYPE={WRQ:"WRQ",ACK:"ACK",ERROR:"ERROR",CANCEL:"CANCEL",MESSAGE:"MESSAGE"},Skylink.prototype.sendBlobData=function(data,timeout,targetPeerId,sendChunksAsBinary,callback){this._startDataTransfer(data,timeout,targetPeerId,sendChunksAsBinary,callback,"blob")},Skylink.prototype.sendURLData=function(data,timeout,targetPeerId,callback){this._startDataTransfer(data,timeout,targetPeerId,callback,null,"data")},Skylink.prototype.respondBlobRequest=Skylink.prototype.acceptDataTransfer=function(peerId,transferId,accept){var self=this;if("string"!=typeof transferId&&"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as data transfer ID or peer ID is not provided"]);if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as Peer does not have any Datachannel connections"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as invalid transfer ID is provided"]);var channelProp="main";if(self._dataChannels[peerId][transferId]&&(channelProp=transferId),accept){log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]);var dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){console.info(evtPeerId,error,cN,cT),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD,message:new Error("Data transfer terminated as Peer Datachannel connection closed abruptly.")})};self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_STATE.MESSAGING:channelName===transferId)&&[self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED,self.DATA_CHANNEL_STATE.ERROR].indexOf(state)>-1:void self.off("dataChannelState",dataChannelStateCbFn)}),self.once("dataTransferState",function(){dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),delete self._dataTransfers[transferId],self._dataChannels[peerId]&&("main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),channelProp===transferId&&self._closeDataChannel(peerId,transferId))},function(state,evtTransferId,evtPeerId){return evtTransferId===transferId&&evtPeerId===peerId&&[self.DATA_TRANSFER_STATE.ERROR,self.DATA_TRANSFER_STATE.CANCEL,self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED].indexOf(state)>-1}),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:0},channelProp),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_STARTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)}else log.warn([peerId,"RTCDataChannel",transferId,"Rejected data transfer and data transfer request has been aborted"]),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:-1},channelProp),"main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.USER_REJECTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as User has rejected data transfer request."),transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD}),delete self._dataTransfers[transferId]},Skylink.prototype.cancelBlobTransfer=Skylink.prototype.cancelDataTransfer=function(peerId,transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer ID is not provided"]);if(!peerId||"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as peer ID is not provided"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer session does not exists."]);log.debug([peerId,"RTCDataChannel",transferId,"Canceling data transfer ..."]);var emitEventFn=function(peers,transferInfoPeerId){for(var i=0;i0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},"main"),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},transferId),emitEventFn(Object.keys(self._dataTransfers[transferId].peers.main).concat(Object.keys(self._dataTransfers[transferId].peers[transferId])))}else{var channelProp="main";if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as Peer does not have any Datachannel connections"]);self._dataChannels[peerId][transferId]&&(channelProp=transferId),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},channelProp),emitEventFn([peerId],peerId)}},Skylink.prototype.sendP2PMessage=function(message,targetPeerId){var listOfPeers=Object.keys(this._dataChannels),isPrivate=!1;if(Array.isArray(targetPeerId)?(listOfPeers=targetPeerId,isPrivate=!0):targetPeerId&&"string"==typeof targetPeerId&&(listOfPeers=[targetPeerId],isPrivate=!0),!this._inRoom||!this._user||!this._user.sid)return void log.error("Unable to send message as User is not in Room. ->",message);if(!this._enableDataChannel)return void log.error("Unable to send message as User does not have Datachannel enabled. ->",message);for(var i=0;i-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeStreamingFn=function(error){log.error(error)};if(!this._inRoom||!this._user||!this._user.sid)return emitErrorBeforeStreamingFn("Unable to start data streaming as User is not in Room.");if(!this._enableDataChannel)return emitErrorBeforeStreamingFn("Unable to start data streaming as User does not have Datachannel enabled.");if(0===listOfPeers.length)return emitErrorBeforeStreamingFn("Unable to start data streaming as there are no Peers to start session with.");if(self._hasMCU)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature is current not supported by MCU yet.");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},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"===window.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE)};if(peersNonInterop.length>0)if(self._hasMCU)waitForChannelOpenFn("MCU",peersNonInterop);else for(var pni=0;pni0)if(self._hasMCU)startDataSessionFn("MCU","main",peersInterop);else for(var pi=0;piself._CHUNK_DATAURL_SIZE:updatedDataChunk.length>self._BINARY_FILE_SIZE)return void log.error("Failed streaming data chunk as data chunk exceeds maximum chunk limit.");var sessionInfo={chunk:updatedDataChunk,chunkSize:updatedDataChunk.size||updatedDataChunk.length||updatedDataChunk.byteLength,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){var onSendDataFn=function(buffer){self._sendMessageToDataChannel(peerId,buffer,channelProp,!0);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i-1&&"string"!=typeof dataChunk?new Int8Array(dataChunk):dataChunk:new Blob([dataChunk]))};for(var peerId in self._dataStreams[transferId].sessions)if(self._dataStreams[transferId].sessions.hasOwnProperty(peerId)&&self._dataStreams[transferId].sessions[peerId]){var channelProp=self._dataStreams[transferId].sessions[peerId];if(!self._dataChannels[self._hasMCU?"MCU":peerId]||!self._dataChannels[self._hasMCU?"MCU":peerId][channelProp]||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].channel.readyState!==self.DATA_CHANNEL_STATE.OPEN||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].streamId!==transferId)return log.error([peerId,"RTCDataChannel",transferId,"Failed streaming data as it has not started or is ready."]),void self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,peerId,sessionInfo,new Error("Streaming as it has not started or Datachannel connection is not open."));self._hasMCU?"main"===channelProp?peersInterop.push(peerId):peersNonInterop.push(peerId):sendDataFn(peerId,channelProp)}self._hasMCU&&(peersInterop.length>0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype.stopStreamingData=function(transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error("Failed streaming data chunk as stream session ID is not provided.");if(!(self._inRoom&&self._user&&self._user.sid))return void log.error("Failed streaming data chunk as User is not in the Room.");if(!self._dataStreams[transferId])return void log.error("Failed stopping data streaming session as it does not exists.");if(!self._dataStreams[transferId].isUpload)return void log.error("Failed stopping data streaming session as it is not sending.");if(self._hasMCU)return void log.error("Failed stopping data streaming session as MCU does not support this feature yet.");var sessionInfo={chunk:null,chunkSize:0,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:transferId,size:0,originalSize:0,dataType:"fastBinaryStop",mimeType:null,chunkType:self._dataStreams[transferId].sessionChunkType,chunkSize:0,timeout:0,isPrivate:self._dataStreams[transferId].isPrivate,sender:self._user.sid,agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers||peerId},channelProp);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype._startDataTransfer=function(data,timeout,targetPeerId,sendChunksAsBinary,callback,sessionType){var self=this,transferId=(self._user?self._user.sid:"")+"_"+(new Date).getTime(),transferErrors={},transferCompleted=[],chunks=[],listOfPeers=Object.keys(self._peerConnections),sessionChunkType="string",transferInfo={name:null,size:null,chunkSize:null,chunkType:null,dataType:null,mimeType:null,direction:self.DATA_TRANSFER_TYPE.UPLOAD,timeout:60,isPrivate:!1,percentage:0};"number"==typeof timeout?transferInfo.timeout=timeout:Array.isArray(timeout)?listOfPeers=timeout:timeout&&"string"==typeof timeout?listOfPeers=[timeout]:timeout&&"boolean"==typeof timeout?sessionChunkType="binary":"function"==typeof timeout&&(callback=timeout),Array.isArray(targetPeerId)?listOfPeers=targetPeerId:targetPeerId&&"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:targetPeerId&&"boolean"==typeof targetPeerId?sessionChunkType="binary":"function"==typeof targetPeerId&&(callback=targetPeerId),sendChunksAsBinary&&"boolean"==typeof sendChunksAsBinary?sessionChunkType="binary":"function"==typeof sendChunksAsBinary&&(callback=sendChunksAsBinary),listOfPeers.indexOf("MCU")>-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeDataTransferFn=function(error){if(log.error(error),"function"==typeof callback){var transferErrors={};if(0===listOfPeers.length)transferErrors.self=new Error(error);else for(var i=0;i0){var bsChunkSize="firefox"===window.webrtcDetectedBrowser?self._MOZ_CHUNK_FILE_SIZE:self._CHUNK_FILE_SIZE,bsChunks=self._chunkBlobData(new Blob(chunks),bsChunkSize);self._dataTransfers[transferId].enforceBSInfo={chunkSize:4*Math.ceil(bsChunkSize/3),chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,size:4*Math.ceil(transferInfo.originalSize/3),chunks:bsChunks}}}for(var completeFn=function(peerId,error){transferCompleted.indexOf(peerId)>-1||(log.debug([peerId,"RTCDataChannel",transferId,"Data transfer result. Is errors present? ->"],error),transferCompleted.push(peerId),error&&(transferErrors[peerId]=new Error(error)),listOfPeers.length===transferCompleted.length&&(log.log([null,"RTCDataChannel",transferId,"Data transfer request completed"]),"function"==typeof callback&&(Object.keys(transferErrors).length>0?callback({transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),transferErrors:transferErrors,listOfPeers:listOfPeers},null):callback(null,{transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),listOfPeers:listOfPeers}))))},i=0;i0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,"main",Object.keys(self._dataTransfers[transferId].peers.main)),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,transferId,Object.keys(self._dataTransfers[transferId].peers[transferId])))},Skylink.prototype._startDataTransferToPeer=function(transferId,peerId,callback,channelProp,targetPeers){var self=this,peerConnectionStateCbFn=null,dataChannelStateCbFn=null,emitEventFn=function(cb){for(var peers=targetPeers||[peerId],i=0;i-1&&(log.warn([peerId,"RTCDataChannel",transferId,"Binary data chunks transfer is not yet supported with Peer connecting from Android, iOS and C++ SDK. Fallbacking to binary string data chunks transfer."]),size=self._dataTransfers[transferId].enforceBSInfo.size,chunkSize=self._dataTransfers[transferId].enforceBSInfo.chunkSize,chunkType="string"),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:self._dataTransfers[transferId].name,size:size,originalSize:self._dataTransfers[transferId].originalSize,dataType:self._dataTransfers[transferId].sessionType,mimeType:self._dataTransfers[transferId].mimeType,chunkType:chunkType,chunkSize:chunkSize,timeout:self._dataTransfers[transferId].timeout,isPrivate:self._dataTransfers[transferId].isPrivate,sender:self._user.sid,agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers||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");return self._isLowerThanVersion(protocolVer,"0.1.2")&&"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer do not support DATA_URL type of data transfers"):"MCU"!==peerId&&self._hasMCU?(channelProp=requireInterop?"main":transferId,peerConnectionStateCbFn=function(){returnErrorBeforeTransferFn("Data transfer terminated as Peer connection is not stable.")},self.once("peerConnectionState",peerConnectionStateCbFn,function(state,evtPeerId){return self._dataTransfers[transferId]?state!==self.PEER_CONNECTION_STATE.STABLE&&evtPeerId===peerId:void self.off("peerConnectionState",peerConnectionStateCbFn)}),requireInterop):(requireInterop||"main"===channelProp)&&self._dataChannels[peerId].main.transferId?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel has a data transfer in-progress."):(self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0},dataChannelStateCbFn=function(state,evtPeerId,error){self._dataTransfers[transferId].sessions[peerId].ackN>=self._dataTransfers[transferId].chunks.length-1||returnErrorBeforeTransferFn(error?error.message||error.toString():"Data transfer terminated as Peer Datachannel connection closed abruptly.")},self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName===transferId?(self._dataChannels[peerId][channelProp].transferId=transferId,sendWRQFn(),!1):[self.DATA_CHANNEL_STATE.CREATE_ERROR,self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1:void self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(self._dataChannels[peerId].main.transferId=transferId,sendWRQFn()):(channelProp=transferId,self._createDataChannel(peerId,transferId,"data"===self._dataTransfers[transferId].sessionType?self._CHUNK_DATAURL_SIZE:"string"===self._dataTransfers[transferId].sessionChunkType?"firefox"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE))))},Skylink.prototype._getTransferInfo=function(transferId,peerId,returnDataProp,hidePercentage,returnDataAtStart){if(!this._dataTransfers[transferId])return{};var transferInfo={name:this._dataTransfers[transferId].name,size:this._dataTransfers[transferId].size,dataType:this._dataTransfers[transferId].dataType||this.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:this._dataTransfers[transferId].mimeType||null,chunkSize:this._dataTransfers[transferId].chunkSize,chunkType:this._dataTransfers[transferId].chunkType,timeout:this._dataTransfers[transferId].timeout,isPrivate:this._dataTransfers[transferId].isPrivate,direction:this._dataTransfers[transferId].direction};if(this._dataTransfers[transferId].originalSize?transferInfo.size=this._dataTransfers[transferId].originalSize:this._dataTransfers[transferId].chunkType===this.DATA_TRANSFER_DATA_TYPE.BINARY_STRING&&(transferInfo.size=Math.ceil(3*transferInfo.size/4)),!hidePercentage){if(transferInfo.percentage=0,!this._dataTransfers[transferId].sessions[peerId])return returnDataProp&&(transferInfo.data=null),transferInfo;if(this._dataTransfers[transferId].direction===this.DATA_TRANSFER_TYPE.DOWNLOAD)this._dataTransfers[transferId].sessions[peerId].receivedSize===this._dataTransfers[transferId].sessions[peerId].size?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].receivedSize/this._dataTransfers[transferId].size*100).toFixed(2),10);else{var chunksLength=this._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?this._dataTransfers[transferId].enforceBSInfo.chunks.length:this._dataTransfers[transferId].chunks.length;this._dataTransfers[transferId].sessions[peerId].ackN===chunksLength?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].ackN/chunksLength*100).toFixed(2),10)}returnDataProp&&("number"!=typeof returnDataAtStart?100===transferInfo.percentage?transferInfo.data=this._getTransferData(transferId):transferInfo.data=null:(transferInfo.percentage=returnDataAtStart,0===returnDataAtStart&&(transferInfo.data=this._getTransferData(transferId))))}return transferInfo},Skylink.prototype._getTransferData=function(transferId){if(!this._dataTransfers[transferId])return null;if(this._dataTransfers[transferId].dataType===this.DATA_TRANSFER_SESSION_TYPE.BLOB){var mimeType={name:this._dataTransfers[transferId].name};return this._dataTransfers[transferId].mimeType&&(mimeType.type=this._dataTransfers[transferId].mimeType),new Blob(this._dataTransfers[transferId].chunks,mimeType)}return this._dataTransfers[transferId].chunks.join("")},Skylink.prototype._handleDataTransferTimeoutForPeer=function(transferId,peerId,setPeerTO){var self=this;if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer does not exists for Peer. Ignoring timeout."]);log.debug([peerId,"RTCDataChannel",transferId,"Clearing data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer&&clearTimeout(self._dataTransfers[transferId].sessions[peerId].timer),self._dataTransfers[transferId].sessions[peerId].timer=null,setPeerTO&&(log.debug([peerId,"RTCDataChannel",transferId,"Setting data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer=setTimeout(function(){if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer already ended for Peer. Ignoring expired timeout."]);if(!self._user||!self._user.sid)return void log.debug([peerId,"RTCDataChannel",transferId,"User is not in Room. Ignoring expired timeout."]);if(!self._dataChannels[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Datachannel connection does not exists. Ignoring expired timeout."]);log.error([peerId,"RTCDataChannel",transferId,"Data transfer response has timed out."]);var 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"===window.webrtcDetectedBrowser){if(window.BlobBuilder){var bb=new BlobBuilder;bb.append(rawData.constructor&&"ArrayBuffer"===rawData.constructor.name?byteArray:new Uint8Array(byteArray).buffer),blob=bb.getBlob()}}else blob=new Blob([byteArray]);log.debug([peerId,"RTCDataChannel",channelProp,"Received arraybuffer data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],blob.size),self._DATAProtocolHandler(peerId,blob,self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,blob.size,channelProp)}}},Skylink.prototype._WRQProtocolHandler=function(peerId,data,channelProp){var self=this,transferId="main"===channelProp?data.transferId||null:channelProp,senderPeerId=data.sender||peerId;if(["fastBinaryStart","fastBinaryStop"].indexOf(data.dataType)>-1)if("fastBinaryStart"===data.dataType){transferId||(transferId="stream_"+peerId+"_"+(new Date).getTime()),self._dataStreams[transferId]={chunkSize:0,chunkType:"string"===data.chunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:data.chunkType,isPrivate:!!data.isPrivate,isStringStream:"string"===data.chunkType,senderPeerId:senderPeerId,isUpload:!1},self._dataChannels[peerId][channelProp].streamId=transferId;self.once("dataChannelState",function(){},function(state,evtPeerId,channelName,channelType,error){if(!self._dataStreams[transferId])return!0;if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId&&channelType===self.DATA_CHANNEL_TYPE.DATA)&&[self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');return self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},updatedError),!0}}),self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STARTED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStarted",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1)}else transferId=self._dataChannels[peerId][channelProp].streamId,self._dataStreams[transferId]&&!self._dataStreams[transferId].isUpload&&(self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STOPPED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStopped",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1),self._dataChannels[peerId][channelProp].streamId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp),delete self._dataStreams[transferId]);else transferId||(transferId="transfer_"+peerId+"_"+(new Date).getTime()),self._dataTransfers[transferId]={name:data.name||transferId,size:data.size||0,chunkSize:data.chunkSize,originalSize:data.originalSize||0,timeout:data.timeout||60,isPrivate:!!data.isPrivate,senderPeerId:data.sender||peerId,dataType:self.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:data.mimeType||null,chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,direction:self.DATA_TRANSFER_TYPE.DOWNLOAD,chunks:[],sessions:{},sessionType:data.dataType||"blob",sessionChunkType:data.chunkType||"string"},"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?(self._dataTransfers[transferId].dataType=self.DATA_TRANSFER_SESSION_TYPE.DATA_URL,self._dataTransfers[transferId].chunkType=self.DATA_TRANSFER_DATA_TYPE.STRING):"blob"===self._dataTransfers[transferId].sessionType&&"binary"===self._dataTransfers[transferId].sessionChunkType&&(self._dataTransfers[transferId].chunkType=self._binaryChunkType),self._dataChannels[peerId][channelProp].transferId=transferId,self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0,receivedSize:0},self._trigger("incomingDataRequest",transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!1),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_REQUEST,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)},Skylink.prototype._ACKProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ACK event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};if(data.ackN>-1){if(0===data.ackN)emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_STARTED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,0),null)});else if(self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?data.ackN===self._dataTransfers[transferId].enforceBSInfo.chunks.length:data.ackN===self._dataTransfers[transferId].chunks.length)return self._dataTransfers[transferId].sessions[peerId].ackN=data.ackN,emitEventFn(function(evtPeerId){self._trigger("incomingData",self._getTransferData(transferId),transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,100),null)}),void(self._dataChannels[peerId][channelProp]&&(self._dataChannels[peerId][channelProp].transferId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp)));var uploadFn=function(chunk){self._sendMessageToDataChannel(peerId,chunk,channelProp,!0),data.ackN-1?self._blobToBase64(self._dataTransfers[transferId].enforceBSInfo.chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING?self._blobToBase64(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER?self._blobToArrayBuffer(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):uploadFn(self._dataTransfers[transferId].chunks[data.ackN])}else self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.REJECTED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as Peer has rejected data transfer request"),transferType:self.DATA_TRANSFER_TYPE.UPLOAD})},Skylink.prototype._MESSAGEProtocolHandler=function(peerId,data,channelProp){var senderPeerId=data.sender||peerId;log.log([senderPeerId,"RTCDataChannel",channelProp,"Received P2P message from peer:"],data),this._trigger("incomingMessage",{content:data.data,isPrivate:data.isPrivate,isDataChannel:!0,targetPeerId:this._user.sid,senderPeerId:senderPeerId},senderPeerId,this.getPeerInfo(senderPeerId),!1)},Skylink.prototype._ERRORProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,userInfo:self._getUserInfo(targetMid),target:targetMid,rid:self._room.id})}}},Skylink.prototype._addIceCandidateToQueue=function(targetMid,canId,candidate){var candidateType=candidate.candidate.split(" ")[7];log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Buffering ICE candidate."]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.BUFFERED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[],this._peerCandidatesQueue[targetMid].push([canId,candidate])},Skylink.prototype._addIceCandidateFromQueue=function(targetMid){this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[];for(var i=0;i"],error),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESS_ERROR,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},error)};if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Adding ICE candidate."]),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESSING,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[targetMid].remoteDescription&&self._peerConnections[targetMid].remoteDescription.sdp&&self._peerConnections[targetMid].remoteDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),void self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),-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"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}},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"===window.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;if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]),"edge"===window.webrtcDetectedBrowser)return callback(new Error("Edge does not support stats"));if(!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},Skylink.prototype._addPeer=function(targetMid,cert,peerBrowser,receiveOnly,isSS){var self=this;return self._peerConnections[targetMid]?void log.error([targetMid,null,null,"Connection to peer has already been made"]):(self._peerConnStatus[targetMid]={connected:!1,init:!1},log.log([targetMid,null,null,"Starting the connection to peer. Options provided:"],{peerBrowser:peerBrowser,receiveOnly:receiveOnly,enableDataChannel:self._enableDataChannel}),log.info("Adding peer",isSS),self._peerConnections[targetMid]=self._createPeerConnection(targetMid,!!isSS,cert),self._peerConnections[targetMid]?(self._peerConnStatus[targetMid].init=!0,void(self._peerConnections[targetMid].hasScreen=!!isSS)):void log.error([targetMid,null,null,"Failed creating the connection to peer."]))},Skylink.prototype._restartPeerConnection=function(peerId,doIceRestart,bwOptions,callback){var self=this;if(!self._peerConnections[peerId])return void log.error([peerId,null,null,"Peer does not have an existing connection. Unable to restart"]);var pc=self._peerConnections[peerId],agent=(self.getPeerInfo(peerId)||{}).agent||{};if(self._isLowerThanVersion(agent.SMProtocolVersion||"","0.1.2")){var notSupportedError=new Error("Failed restarting with other agents connecting from other SDKs as re-negotiation is not supported by other SDKs");return log.warn([peerId,"RTCPeerConnection",null,"Ignoring restart request as agent's SDK does not support it"],notSupportedError),void("function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(notSupportedError)))}if(pc.signalingState===self.PEER_CONNECTION_STATE.STABLE&&self._peerConnections[peerId]){log.log([peerId,null,null,"Sending restart message to signaling server ->"],{iceRestart:doIceRestart,options:bwOptions}),self._peerCustomConfigs[peerId]=self._peerCustomConfigs[peerId]||{},self._peerCustomConfigs[peerId].bandwidth=self._peerCustomConfigs[peerId].bandwidth||{},self._peerCustomConfigs[peerId].googleXBandwidth=self._peerCustomConfigs[peerId].googleXBandwidth||{},bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._peerCustomConfigs[peerId].bandwidth.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._peerCustomConfigs[peerId].bandwidth.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._peerCustomConfigs[peerId].bandwidth.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._peerCustomConfigs[peerId].googleXBandwidth.min=bwOptions.googleXBandwidth.min), -"number"==typeof bwOptions.googleXBandwidth.max&&(self._peerCustomConfigs[peerId].googleXBandwidth.max=bwOptions.googleXBandwidth.max));var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!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(),"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,self._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}},self._streamsSession[targetMid]=self._streamsSession[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._sdpSessions[targetMid]={local:{},remote:{}},self._peerBandwidth[targetMid]={};var bandwidth=null;return pc.ondatachannel=function(event){var dc=event.channel||event;if(log.debug([targetMid,"RTCDataChannel",dc.label,"Received datachannel ->"],dc),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel){self.DATA_CHANNEL_TYPE.DATA,dc.label;pc.hasMainChannel||(self.DATA_CHANNEL_TYPE.MESSAGING,"main",pc.hasMainChannel=!0),self._createDataChannel(targetMid,dc)}else log.warn([targetMid,"RTCDataChannel",dc.label,"Not adding datachannel as enable datachannel is set to false"])},pc.onaddstream=function(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&-1===pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" "))return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},pc.onicecandidate=function(event){self._onIceCandidate(targetMid,event.candidate||event)},pc.oniceconnectionstatechange=function(evt){var iceConnectionState=pc.iceConnectionState;if(log.debug([targetMid,"RTCIceConnectionState",null,"Ice connection state changed ->"],iceConnectionState),"edge"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._enableIceTrickle&&self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.TRICKLE_FAILED,targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].connected=[self.ICE_CONNECTION_STATE.COMPLETED,self.ICE_CONNECTION_STATE.CONNECTED].indexOf(iceConnectionState)>-1),!self._hasMCU&&[self.ICE_CONNECTION_STATE.CONNECTED,self.ICE_CONNECTION_STATE.COMPLETED].indexOf(iceConnectionState)>-1&&self._bandwidthAdjuster&&!bandwidth&&"edge"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),self._trigger("peerConnectionState",pc.signalingState,targetMid)},pc.onicegatheringstatechange=function(){log.log([targetMid,"RTCIceGatheringState",null,"Ice gathering state changed ->"],pc.iceGatheringState),self._trigger("candidateGenerationState",pc.iceGatheringState,targetMid)},"firefox"===window.webrtcDetectedBrowser&&(pc.removeStream=function(stream){for(var senders=pc.getSenders(),s=0;s"],restartMsg),self._sendChannelMessage(restartMsg)};bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=bwOptions.googleXBandwidth.max));for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers},null):callback(null,{listOfPeers:listOfPeers}))};self.once("peerJoined",peerJoinedFn,function(peerId,peerInfo,isSelf){return isSelf}),self.leaveRoom(!1,function(error,success){if(error){if("function"==typeof callback){for(var i=0;i=self._peerEndOfCandidatesCounter[targetMid].expectedLen&&(!self._peerCandidatesQueue[targetMid]||0===self._peerCandidatesQueue[targetMid].length)&&!self._peerEndOfCandidatesCounter[targetMid].hasSet){log.debug([targetMid,"RTCPeerConnection",null,"Signaling of end-of-candidates remote ICE gathering."]),self._peerEndOfCandidatesCounter[targetMid].hasSet=!0;try{if("edge"===window.webrtcDetectedBrowser){for(var mLineCounter=-1,addedMids=[],sdpLines=self._peerConnections[targetMid].remoteDescription.sdp.split("\r\n"),rejected=!1,i=0;i"],error)}}},Skylink.prototype.setUserData=function(userData){var self=this,updatedUserData="";void 0!==userData&&null!==userData&&(updatedUserData=userData),this._userData=updatedUserData,self._inRoom?(log.log("Updated userData -> ",updatedUserData),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.UPDATE_USER,mid:self._user.sid,rid:self._room.id,userData:updatedUserData,stamp:(new Date).getTime()}),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0)):log.warn("User is not in the room. Broadcast of updated information will be dropped")},Skylink.prototype.getUserData=function(peerId){if(peerId&&this._peerInformations[peerId]){var userData=this._peerInformations[peerId].userData;return null!==userData&&void 0===userData||(userData=""),userData}return this._userData},Skylink.prototype.getPeerInfo=function(peerId){var peerInfo=null;return"string"==typeof peerId&&"object"==typeof this._peerInformations[peerId]?(peerInfo=clone(this._peerInformations[peerId]),peerInfo.room=clone(this._selectedRoom),peerInfo.settings.bandwidth=peerInfo.settings.bandwidth||{},peerInfo.settings.googleXBandwidth=peerInfo.settings.googleXBandwidth||{},"boolean"==typeof peerInfo.settings.video||peerInfo.settings.video&&"object"==typeof peerInfo.settings.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"==typeof peerInfo.settings.audio||peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.audioMuted&&(peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.videoMuted&&(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.maxBandwidth&&(peerInfo.settings.bandwidth=clone(peerInfo.settings.maxBandwidth),delete peerInfo.settings.maxBandwidth),peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&peerInfo.settings.video.customSettings&&"object"==typeof peerInfo.settings.video.customSettings&&(peerInfo.settings.video.customSettings.frameRate&&(peerInfo.settings.video.frameRate=clone(peerInfo.settings.video.customSettings.frameRate)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode)),peerInfo.settings.video.customSettings.width&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.width=clone(peerInfo.settings.video.customSettings.width)),peerInfo.settings.video.customSettings.height&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.height=clone(peerInfo.settings.video.customSettings.height)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode))),peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&(peerInfo.settings.audio.stereo=!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)),this._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0)):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,os:window.navigator.platform,pluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:this.SMProtocolVersion,DTProtocolVersion:this.DTProtocolVersion},room:clone(this._selectedRoom),config:{enableDataChannel:this._enableDataChannel,enableIceTrickle:this._enableIceTrickle,enableIceRestart:this._enableIceRestart,priorityWeight:this._peerPriorityWeight,receiveOnly:!1,publishOnly:!!this._publishOnly},connected:null,init:null},null!==peerInfo.userData&&void 0!==peerInfo.userData||(peerInfo.userData=""),this._streams.screenshare?peerInfo.settings=clone(this._streams.screenshare.settings):this._streams.userMedia&&(peerInfo.settings=clone(this._streams.userMedia.settings)),peerInfo.settings.bandwidth=clone(this._streamsBandwidthSettings.bAS),peerInfo.settings.googleXBandwidth=clone(this._streamsBandwidthSettings.googleX),peerInfo.parentId=this._parentId?this._parentId:null,peerInfo.config.receiveOnly=!peerInfo.settings.video&&!peerInfo.settings.audio,peerInfo.settings.data=this._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._codecParams.audio.opus.useinbandfec))),peerInfo.settings.audio||(peerInfo.mediaStatus.audioMuted=!0),peerInfo.settings.video||(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.audio||peerInfo.settings.video||(peerInfo.config.receiveOnly=!0,peerInfo.config.publishOnly=!1),peerInfo},Skylink.prototype.getPeersInRoom=function(){for(var listOfPeersInfo={},listOfPeers=Object.keys(this._peerInformations),i=0;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i-1||(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.settings.video&&!self._getSDPEdgeVideoSupports(usePeerId)&&(customSettings.settings.video=!1,customSettings.mediaStatus.videoMuted=!0),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),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype.HANDSHAKE_PROGRESS={ENTER:"enter",WELCOME:"welcome",OFFER:"offer",ANSWER:"answer",ERROR:"error"},Skylink.prototype._doOffer=function(targetMid,iceRestart,peerBrowser){var self=this,pc=self._peerConnections[targetMid];if(log.log([targetMid,null,null,"Checking caller status"],peerBrowser),!pc)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of creating of offer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription","offer",'Dropping of creating of offer as signalingState is not "'+self.PEER_CONNECTION_STATE.STABLE+'" ->'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._dataChannels[targetMid]&&self._dataChannels[targetMid].main||(self._createDataChannel(targetMid),self._peerConnections[targetMid].hasMainChannel=!0)),log.debug([targetMid,null,null,"Creating offer with config:"],offerConstraints),pc.endOfCandidates=!1,self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=offerConstraints),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},offerConstraints)},Skylink.prototype._doAnswer=function(targetMid){var self=this;log.log([targetMid,null,null,"Creating answer with config:"],self._room.connection.sdpConstraints);var pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of creating of answer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription","answer",'Dropping of creating of answer as signalingState is not "'+self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER+'" ->'],pc.signalingState);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,_sessionDescription){var self=this,pc=self._peerConnections[targetMid];if(!_sessionDescription||!_sessionDescription.sdp)return void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],_sessionDescription);if(!pc)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as connection does not exists ->"],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(pc.processingLocalSDP)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as another is being processed ->"],_sessionDescription);pc.processingLocalSDP=!0;var sessionDescription={type:_sessionDescription.type,sdp:_sessionDescription.sdp};sessionDescription.sdp=self._removeSDPFirefoxH264Pref(targetMid,sessionDescription),sessionDescription.sdp=self._setSDPCodecParams(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPUnknownAptRtx(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPCodecs(targetMid,sessionDescription),sessionDescription.sdp=self._handleSDPConnectionSettings(targetMid,sessionDescription,"local"),sessionDescription.sdp=self._removeSDPREMBPackets(targetMid,sessionDescription),log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description updated ->"],sessionDescription.sdp),pc.setLocalDescription(new RTCSessionDescription(sessionDescription),function(){if(log.debug([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description has been set ->"],sessionDescription),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",sessionDescription.type,targetMid),sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER?pc.setAnswer="local":pc.setOffer="local",!self._enableIceTrickle&&!pc.gathered)return void log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description sending is halted to complete ICE gathering."]);self._sendChannelMessage({type:sessionDescription.type,sdp:self._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},function(error){log.error([targetMid,"RTCSessionDescription",sessionDescription.type,"Local description failed setting ->"],error),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)})},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._appKey?("function"==typeof showAll&&(callback=showAll,showAll=!1),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.GET_PEERS,showAll:showAll||!1}),self._trigger("getPeersStateChange",self.GET_PEERS_STATE.ENQUIRED,self._user.sid,null),log.log("Enquired server for peers within the realm"),void("function"==typeof callback&&self.once("getPeersStateChange",function(state,privilegedPeerId,peerList){callback(null,peerList)},function(state,privilegedPeerId,peerList){return state===self.GET_PEERS_STATE.RECEIVED}))):void log.warn("App key is not defined. Please authenticate again."):void log.warn("Please upgrade your key to privileged to use this function")},Skylink.prototype.introducePeer=function(sendingPeerId,receivingPeerId){var self=this;if(!self._isPrivileged)return log.warn("Please upgrade your key to privileged to use this function"),void self._trigger("introduceStateChange",self.INTRODUCE_STATE.ERROR,self._user.sid,sendingPeerId,receivingPeerId,"notPrivileged");self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.INTRODUCE,sendingPeerId:sendingPeerId,receivingPeerId:receivingPeerId}),self._trigger("introduceStateChange",self.INTRODUCE_STATE.INTRODUCING,self._user.sid,sendingPeerId,receivingPeerId,null),log.log("Introducing",sendingPeerId,"to",receivingPeerId)},Skylink.prototype.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};room&&"string"==typeof room?selectedRoom=room:room&&"object"==typeof room?mediaOptions=room:"function"==typeof room&&(callback=room),options&&"object"==typeof options?mediaOptions=options:"function"==typeof options&&(callback=options);var resolveAsErrorFn=function(error,tryRoom,readyState){log.error(error),"function"==typeof callback&&callback({room:tryRoom,errorCode:readyState||null,error: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("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.23",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;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,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={ -stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,maxplaybackrate:"number"==typeof options.codecParams.audio.opus.maxplaybackrate&&options.codecParams.audio.opus.maxplaybackrate>=8e3&&options.codecParams.audio.opus.maxplaybackrate<=48e3?options.codecParams.audio.opus.maxplaybackrate:null,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),!0===forceTURN&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,self._useEdgeWebRTC=useEdgeWebRTC,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}),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})):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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"Network error occurred. (Status: "+xhr.status+")",errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom)},xhr.onprogress=function(){log.debug([null,"XMLHttpRequest",method,"Retrieving information and config from webserver. Url:"],url),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},Skylink.prototype._parseInfo=function(info){if(log.log("Parsing parameter from server",info),!info.pc_constraints&&!info.offer_constraints)return void this._trigger("readyStateChange",this.READY_STATE_CHANGE.ERROR,{status:200,content:info.info,errorCode:info.error},self._selectedRoom);log.debug("Peer connection constraints:",info.pc_constraints),log.debug("Offer constraints:",info.offer_constraints),this._key=info.cid,this._appKeyOwner=info.apiOwner,this._signalingServer=info.ipSigserver,this._isPrivileged=info.isPrivileged,this._autoIntroduce=info.autoIntroduce,this._user={uid:info.username,token:info.userCred,timeStamp:info.timeStamp,streams:[],info:{}},this._room={id:info.room_key,token:info.roomCred,startDateTime:info.start,duration:info.len,connection:{peerConstraints:JSON.parse(info.pc_constraints),peerConfig:null,offerConstraints:JSON.parse(info.offer_constraints),sdpConstraints:{mandatory:{OfferToReceiveAudio:!0,OfferToReceiveVideo:!0}},mediaConstraints:JSON.parse(info.media_constraints)}},this._socketPorts={"http:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,this._trigger("readyStateChange",this.READY_STATE_CHANGE.COMPLETED,null,this._selectedRoom),log.info("Parsed parameters from webserver. Ready for web-realtime communication")},Skylink.prototype._loadInfo=function(){var self=this,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!function(){try{var p=new window.RTCPeerConnection(null);return["object","function"].indexOf(typeof p.createOffer)>-1&&null!==p.createOffer}catch(e){return!1}}())return window.RTCPeerConnection&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);self._getCodecsSupport(function(error){return error?(log.error(error),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:error.message||error.toString(),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):0===Object.keys(self._currentCodecSupport.audio).length&&0===Object.keys(self._currentCodecSupport.video).length?(log.error("No audio/video codecs available to start connection."),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No API Path is found",errorCode:self.READY_STATE_CHANGE_ERROR.NO_PATH},self._selectedRoom)):(log.error("XMLHttpRequest not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"XMLHttpRequest not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_XMLHTTPREQUEST_SUPPORT},self._selectedRoom)):(log.error("Socket.io not loaded. Please load socket.io"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"Socket.io not found",errorCode:self.READY_STATE_CHANGE_ERROR.NO_SOCKET_IO},self._selectedRoom))},Skylink.prototype._initSelectedRoom=function(room,callback){var self=this;if("function"==typeof room||void 0===room)return void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null,useEdgeWebRTC:self._useEdgeWebRTC};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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,target:message.target,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._redirectHandler=function(message){if(log.log(["Server",null,message.type,"System action warning:"],{message:message.info,reason:message.reason,action:message.action}),message.action===this.SYSTEM_ACTION.REJECT)for(var key in this._peerConnections)this._peerConnections.hasOwnProperty(key)&&this._removePeer(key);"toClose"===message.reason&&(message.reason="toclose"),this._trigger("systemAction",message.action,message.info,message.reason)},Skylink.prototype._updateUserEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer updated userData:"],message.userData),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].userData=message.stamp}this._peerInformations[targetMid].userData=message.userData||{},this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._roomLockEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,message.type,"Room lock status:"],message.lock),this._trigger("roomLock",message.lock,targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._muteAudioEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's audio muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].audioMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.audioMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,message.type,"Peer does not have any user information"])},Skylink.prototype._muteVideoEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's video muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].videoMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.videoMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._streamEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Peer's stream status:"],message.status),this._peerInformations[targetMid]&&message.streamId?(this._streamsSession[targetMid]=this._streamsSession[targetMid]||{},"ended"===message.status&&(message.settings&&"object"==typeof message.settings&&void 0===this._streamsSession[targetMid][message.streamId]&&(this._streamsSession[targetMid][message.streamId]={audio:message.settings.audio,video:message.settings.video}),this._handleEndedStreams(targetMid,message.streamId))):log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._byeHandler=function(message){var targetMid=message.mid;(this._user||{}).sid!==targetMid?(log.log([targetMid,null,message.type,"Peer has left the room"]),this._removePeer(targetMid)):log.log([targetMid,null,message.type,"Self has left the room"])},Skylink.prototype._privateMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received private message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!0,targetPeerId:message.target,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._publicMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received public message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!1,targetPeerId:null,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._recordingEventHandler=function(message){var self=this;if(log.debug(["MCU","Recording",null,"Received recording message ->"],message),"on"===message.action)self._recordings[message.recordingId]||(log.debug(["MCU","Recording",message.recordingId,"Started recording"]),self._currentRecordingId=message.recordingId,self._recordings[message.recordingId]={active:!0,state:self.RECORDING_STATE.START,startedDateTime:(new Date).toISOString(),endedDateTime:null,mixingDateTime:null,links:null,error:null},self._recordingStartInterval=setTimeout(function(){log.log(["MCU","Recording",message.recordingId,"4 seconds has been recorded. Recording can be stopped now"]),self._recordingStartInterval=null},4e3),self._trigger("recordingState",self.RECORDING_STATE.START,message.recordingId,null,null));else if("off"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,'Received request of "off" but the session is empty']);self._currentRecordingId=null,self._recordingStartInterval&&(clearTimeout(self._recordingStartInterval),log.warn(["MCU","Recording",message.recordingId,"Recording stopped abruptly before 4 seconds"]),self._recordingStartInterval=null),log.debug(["MCU","Recording",message.recordingId,"Stopped recording"]),self._recordings[message.recordingId].active=!1,self._recordings[message.recordingId].state=self.RECORDING_STATE.STOP,self._recordings[message.recordingId].endedDateTime=(new Date).toISOString(),self._trigger("recordingState",self.RECORDING_STATE.STOP,message.recordingId,null,null)}else if("url"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,"Received URL but the session is empty"]);var links={};if(Array.isArray(message.urls))for(var i=0;i"],recordingError);log.error(["MCU","Recording",message.recordingId,"Recording failure ->"],recordingError),self._recordings[message.recordingId].state=self.RECORDING_STATE.ERROR,self._recordings[message.recordingId].error=recordingError,self._recordings[message.recordingId].active&&(log.debug(["MCU","Recording",message.recordingId,"Stopped recording abruptly"]),self._recordings[message.recordingId].active=!1),self._trigger("recordingState",self.RECORDING_STATE.ERROR,message.recordingId,null,recordingError)}},Skylink.prototype._inRoomHandler=function(message){var self=this;log.log(["Server",null,message.type,"User is now in the room and functionalities are now available. Config received:"],message.pc_config),self._room.connection.peerConfig=self._setIceServers(message.pc_config),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.ENFORCE_OFFERER?2e15:-2e15),self._trigger("peerJoined",self._user.sid,self.getPeerInfo(),!0),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,self._user.sid);var streamId=null;self._streams.screenshare&&self._streams.screenshare.stream?(streamId=self._streams.screenshare.stream.id||self._streams.screenshare.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.screenshare.stream,!0,self.getPeerInfo(),!0,streamId)):self._streams.userMedia&&self._streams.userMedia.stream&&(streamId=self._streams.userMedia.stream.id||self._streams.userMedia.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.userMedia.stream,!0,self.getPeerInfo(),!1,streamId));var enterMsg={type:self._SIG_MESSAGE_TYPE.ENTER,mid:self._user.sid,rid:self._room.id,agent:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._enterHandler=function(message){var self=this,targetMid=message.mid,isNewPeer=!1,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),receiveOnly:self.getPeerInfo().config.receiveOnly,os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg),isNewPeer&&self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._restartHandler=function(message){var self=this,targetMid=message.mid,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg)}};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._offerHandler=function(message){var self=this,targetMid=message.mid,pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for offer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}log.log([targetMid,null,message.type,"Received offer from peer. Session description:"],clone(message));var offer={type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};return log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],offer),offer.sdp=self._removeSDPFilteredCandidates(targetMid,offer),offer.sdp=self._setSDPCodec(targetMid,offer),offer.sdp=self._setSDPBitrate(targetMid,offer),offer.sdp=self._setSDPCodecParams(targetMid,offer),offer.sdp=self._removeSDPCodecs(targetMid,offer),offer.sdp=self._removeSDPREMBPackets(targetMid,offer),offer.sdp=self._handleSDPConnectionSettings(targetMid,offer,"remote"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,null,message.type,'Peer connection state is not in "stable" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.resend}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),void pc.setRemoteDescription(new RTCSessionDescription(offer),function(){log.debug([targetMid,"RTCSessionDescription",message.type,"Remote description set"]),pc.setOffer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.OFFER,targetMid),self._addIceCandidateFromQueue(targetMid),self._doAnswer(targetMid)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,offer:offer})}))},Skylink.prototype._candidateHandler=function(message){var targetMid=message.mid;if(!message.candidate&&!message.id)return void log.warn([targetMid,"RTCIceCandidate",null,"Received invalid ICE candidate message ->"],message);var canId="can-"+(new Date).getTime(),candidateType=message.candidate.split(" ")[7]||"",candidate=new RTCIceCandidate({sdpMLineIndex:message.label,candidate:message.candidate,sdpMid:message.id});if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Received ICE candidate ->"],candidate),this._peerEndOfCandidatesCounter[targetMid]=this._peerEndOfCandidatesCounter[targetMid]||{},this._peerEndOfCandidatesCounter[targetMid].len=this._peerEndOfCandidatesCounter[targetMid].len||0,this._peerEndOfCandidatesCounter[targetMid].hasSet=!1,this._peerEndOfCandidatesCounter[targetMid].len++,this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.RECEIVED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!this._peerConnections[targetMid]||this._peerConnections[targetMid].signalingState===this.PEER_CONNECTION_STATE.CLOSED)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed.")),void this._signalingEndOfCandidates(targetMid);if(this._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._forceTURN)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping received ICE candidate as it matches ICE candidate filtering flag ->"],candidate),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Dropping of processing ICE candidate as it matches ICE candidate filtering flag.")),void this._signalingEndOfCandidates(targetMid);log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Not dropping received ICE candidate as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured ->"],candidate)}this._peerConnections[targetMid].remoteDescription&&this._peerConnections[targetMid].remoteDescription.sdp&&this._peerConnections[targetMid].localDescription&&this._peerConnections[targetMid].localDescription.sdp?this._addIceCandidate(targetMid,canId,candidate):this._addIceCandidateToQueue(targetMid,canId,candidate),this._signalingEndOfCandidates(targetMid),this._gatheredCandidates[targetMid]||(this._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),this._gatheredCandidates[targetMid].receiving[candidateType].push({sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex,candidate:candidate.candidate})},Skylink.prototype._answerHandler=function(message){var self=this,targetMid=message.mid;log.log([targetMid,null,message.type,"Received answer from peer. Session description:"],clone(message));var pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for answer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}var answer={type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};return log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],answer),answer.sdp=self._removeSDPFilteredCandidates(targetMid,answer),answer.sdp=self._setSDPCodec(targetMid,answer),answer.sdp=self._setSDPBitrate(targetMid,answer),answer.sdp=self._setSDPCodecParams(targetMid,answer),answer.sdp=self._removeSDPCodecs(targetMid,answer),answer.sdp=self._removeSDPREMBPackets(targetMid,answer),answer.sdp=self._handleSDPConnectionSettings(targetMid,answer,"remote"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?void log.warn([targetMid,null,message.type,'Peer connection state is not in "have-local-offer" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.restart}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),void pc.setRemoteDescription(new RTCSessionDescription(answer),function(){log.debug([targetMid,null,message.type,"Remote description set"]),pc.setAnswer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ANSWER,targetMid),self._addIceCandidateFromQueue(targetMid),self._peerMessagesStamps[targetMid]&&(self._peerMessagesStamps[targetMid].hasRestart=!1),self._dataChannels[targetMid]&&(-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))},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,answer:answer})}))},Skylink.prototype._isLowerThanVersion=function(agentVer,requiredVer){for(var partsA=(agentVer||"").split("."),partsB=(requiredVer||"").split("."),i=0;i0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for sendStream() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream);else{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"===window.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"===window.webrtcDetectedBrowser?(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio=getUserMediaAudioSettings):useMediaSource.indexOf("audio")>-1&&useMediaSource.indexOf("tab")>-1&&(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio={})),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if(hasDefaultAudioTrack||!enableAudioSettings)return void self._onStreamAccessSuccess(stream,settings,!0,!1);settings.getUserMediaSettings.audio=getUserMediaAudioSettings,navigator.getUserMedia({audio:getUserMediaAudioSettings},function(audioStream){try{audioStream.addTrack(stream.getVideoTracks()[0]),self.once("mediaAccessSuccess",function(){self._streams.screenshare.streamClone=stream},function(stream,isScreensharing){return isScreensharing}),self._onStreamAccessSuccess(audioStream,settings,!0,!1)}catch(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.shareScreen)},Skylink.prototype.stopScreen=function(){this._streams.screenshare&&(this._stopStreams({screenshare:!0}),this._inRoom&&(this._streams.userMedia&&this._streams.userMedia.stream&&(this._trigger("incomingStream",this._user.sid,this._streams.userMedia.stream,!0,this.getPeerInfo(),!1,this._streams.userMedia.stream.id||this._streams.userMedia.stream.label),this._trigger("peerUpdated",this._user.sid,this.getPeerInfo(),!0)),this._refreshPeerConnection(Object.keys(this._peerConnections),{},!1)))},Skylink.prototype._muteStreams=function(){var self=this,hasVideo=!1,hasAudio=!1,muteFn=function(stream){for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",self._streamsMutedSettings),{hasVideo:hasVideo,hasAudio:hasAudio}},Skylink.prototype._stopStreams=function(options){var self=this,stopFn=function(stream){var streamId=stream.id||stream.label;log.debug([null,"MediaStream",streamId,"Stopping Stream ->"],stream);try{for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",options)},Skylink.prototype._parseStreamSettings=function(options){var settings={settings:{audio:!1,video:!1},mutedSettings:{shouldAudioMuted:!1,shouldVideoMuted:!1},getUserMediaSettings:{audio:!1,video:!1}};return options.audio&&(settings.settings.audio={stereo:!1,exactConstraints:!!options.useExactConstraints,echoCancellation:!0},settings.getUserMediaSettings.audio={echoCancellation:!0},"object"==typeof options.audio&&("boolean"==typeof options.audio.stereo&&(settings.settings.audio.stereo=options.audio.stereo),"boolean"==typeof options.audio.useinbandfec&&(settings.settings.audio.useinbandfec=options.audio.useinbandfec),"boolean"==typeof options.audio.usedtx&&(settings.settings.audio.usedtx=options.audio.usedtx),"number"==typeof options.audio.maxplaybackrate&&options.audio.maxplaybackrate>=8e3&&options.audio.maxplaybackrate<=48e3&&(settings.settings.audio.maxplaybackrate=options.audio.maxplaybackrate),"boolean"==typeof options.audio.mute&&(settings.mutedSettings.shouldAudioMuted=options.audio.mute),"edge"!==window.webrtcDetectedBrowser&&("boolean"==typeof options.audio.echoCancellation&&(settings.settings.audio.echoCancellation=options.audio.echoCancellation,settings.getUserMediaSettings.audio.echoCancellation=options.audio.echoCancellation),Array.isArray(options.audio.optional)&&(settings.settings.audio.optional=clone(options.audio.optional),settings.getUserMediaSettings.audio.optional=clone(options.audio.optional)),options.audio.deviceId&&"string"==typeof options.audio.deviceId&&"firefox"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,settings.getUserMediaSettings.audio.deviceId=options.useExactConstraints?{exact:options.audio.deviceId}:{ideal:options.audio.deviceId}))),"edge"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio=!0)),options.video&&(settings.settings.video={resolution:clone(this.VIDEO_RESOLUTION.VGA),screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video={},"object"==typeof options.video?("boolean"==typeof options.video.mute&&(settings.mutedSettings.shouldVideoMuted=options.video.mute),Array.isArray(options.video.optional)&&(settings.settings.video.optional=clone(options.video.optional),settings.getUserMediaSettings.video.optional=clone(options.video.optional)),options.video.deviceId&&"string"==typeof options.video.deviceId&&"firefox"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,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&&!self._isUsingPlugin)&&(settings.settings.video.frameRate=options.video.frameRate,settings.getUserMediaSettings.video.frameRate="object"==typeof settings.settings.video.frameRate?settings.settings.video.frameRate:options.useExactConstraints?{exact:settings.settings.video.frameRate}:{max:settings.settings.video.frameRate}), -options.video.facingMode&&["string","object"].indexOf(typeof options.video.facingMode)>-1&&self._isUsingPlugin&&(settings.settings.video.facingMode=options.video.facingMode,settings.getUserMediaSettings.video.facingMode="object"==typeof settings.settings.video.facingMode?settings.settings.video.facingMode:options.useExactConstraints?{exact:settings.settings.video.facingMode}:{max:settings.settings.video.facingMode})):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"===window.webrtcDetectedBrowser&&(settings.settings.video={screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video=!0)),settings},Skylink.prototype._onStreamAccessSuccess=function(stream,settings,isScreenSharing,isAudioFallback){var self=this,streamId=stream.id||stream.label,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(window.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"===window.webrtcDetectedBrowser?stream.endedInterval=setInterval(function(){void 0===stream.recordedTime&&(stream.recordedTime=0),stream.recordedTime===stream.currentTime?(clearInterval(stream.endedInterval),self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])):stream.recordedTime=stream.currentTime},1e3):stream.onended=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},settings.settings.audio&&0===stream.getAudioTracks().length||settings.settings.video&&0===stream.getVideoTracks().length){var tracksNotSameError="Expected audio tracks length with "+(settings.settings.audio?"1":"0")+" and video tracks length with "+(settings.settings.video?"1":"0")+" but received audio tracks length with "+stream.getAudioTracks().length+" and video tracks length with "+stream.getVideoTracks().length;log.warn([null,"MediaStream",streamId,tracksNotSameError]);var requireAudio=!!settings.settings.audio,requireVideo=!!settings.settings.video;settings.settings.audio&&0===stream.getAudioTracks().length&&(settings.settings.audio=!1),settings.settings.video&&0===stream.getVideoTracks().length&&(settings.settings.video=!1),self._trigger("mediaAccessFallback",{error:new Error(tracksNotSameError),diff:{video:{expected:requireVideo?1:0,received:stream.getVideoTracks().length},audio:{expected:requireAudio?1:0,received:stream.getAudioTracks().length}}},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKED,!!isScreenSharing,!!isAudioFallback,streamId)}self._streams[isScreenSharing?"screenshare":"userMedia"]={stream:stream,settings:settings.settings,constraints:settings.getUserMediaSettings},self._muteStreams(),self._trigger("mediaAccessSuccess",stream,!!isScreenSharing,!!isAudioFallback,streamId)},Skylink.prototype._onStreamAccessError=function(error,settings,isScreenSharing){var self=this;if(!isScreenSharing&&settings.settings.audio&&settings.settings.video&&self._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},function(error){log.error("Failed fallbacking to retrieve audio only Stream ->",error),self._trigger("mediaAccessError",error,!1,!0),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.ERROR,!1,!0)});log.error("Failed retrieving "+(isScreenSharing?"screensharing":"camera")+" Stream ->",error),self._trigger("mediaAccessError",error,!!isScreenSharing,!1)},Skylink.prototype._onRemoteStreamAdded=function(targetMid,stream,isScreenSharing){var self=this;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1)},Skylink.prototype._addLocalMediaStreams=function(peerId){var self=this;try{log.log([peerId,null,null,"Adding local stream"]);var pc=self._peerConnections[peerId],offerToReceiveAudio=(self._peerInformations[peerId],self._peerInformations[peerId],!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-1?log.warn([peerId,null,null,"Not re-adding stream as LocalMediaStream is already added"],error):log.error([peerId,null,null,"Failed adding local stream"],error)}},Skylink.prototype._handleEndedStreams=function(peerId,checkStreamId){var self=this;self._streamsSession[peerId]=self._streamsSession[peerId]||{};var renderEndedFn=function(streamId){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){var codecsList=sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codecName+"/"+(samplingRate?samplingRate+("audio"===type?"[/]*.*":".*"):".*")+"\r\n","gi"));if(Array.isArray(codecsList)&&codecsList.length>0)for(var i=0;i0){for(var fmtpParts=(fmtpLine[0].split("a=fmtp:"+payload+" ")[1]||"").replace(/ /g,"").replace(/\r\n/g,"").split(";"),j=0;j0){if(0===sdpLines[i].indexOf("m="))break;0===sdpLines[i].indexOf("c=")?cLineIndex=i:0!==sdpLines[i].indexOf("b=AS:")&&0!==sdpLines[i].indexOf("b:TIAS:")||(sdpLines.splice(i,1),i--)}return"number"==typeof bw&&bw>0?-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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(this._peerInformations[targetMid],this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],compareB.join(" ")),sdpLines.splice(j,0,compareB.join(" ")),j++,mLineIndex++)}for(;this._sdpSessions[targetMid].remote.mLines[mLineIndex+1];){mLineIndex++;var appendIndex=sdpLines.length;sdpLines[appendIndex-1].replace(/\s/gi,"")||(appendIndex-=1);var parts=(this._sdpSessions[targetMid].remote.mLines[mLineIndex]||"").split(" ");parts[1]=0,log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending later rejected m= line ->"],parts.join(" ")),sdpLines.splice(appendIndex,0,parts.join(" "))}}return"edge"!==window.webrtcDetectedBrowser||sessionDescription.type!==this.HANDSHAKE_PROGRESS.OFFER||sdpLines[sdpLines.length-1].replace(/\s/gi,"")||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing last empty space for Edge browsers"]),sdpLines.splice(sdpLines.length-1,1)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "'+codec+'" as it does not exists.']);for(var i=0;i'],payload),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=fmtp:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:\\d+ rtx\\/\\d+\\r\\na=fmtp:\\d+ apt="+payload+"\\r\\n","g"),"");for(var sdpLines=sessionDescription.sdp.split("\r\n"),j=0;j=3&&parts.splice(parts.indexOf(payload),1),sdpLines[j]=parts.join(" ");break}sessionDescription.sdp=sdpLines.join("\r\n")}};return this._disableVideoFecCodecs&&(this._hasMCU?log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "ulpfec" or "red" codecs as connected to MCU to prevent connectivity issues.']):(parseFn("video","red"),parseFn("video","ulpfec"))),this._disableComfortNoiseCodec&&audioSettings&&"object"==typeof audioSettings&&audioSettings.stereo&&parseFn("audio","CN"),"edge"===window.webrtcDetectedBrowser&&"edge"!==(((this._peerInformations[targetMid]||{}).agent||{}).name||"unknown").name&&(sessionDescription.sdp=sessionDescription.sdp.replace(/a=rtcp-fb:.*\ x-message\ .*\r\n/gi,"")),sessionDescription.sdp},Skylink.prototype._removeSDPREMBPackets=function(targetMid,sessionDescription){return this._disableREMB?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing REMB packets."]),sessionDescription.sdp.replace(/a=rtcp-fb:\d+ goog-remb\r\n/g,"")):sessionDescription.sdp},Skylink.prototype._getSDPSelectedCodec=function(targetMid,sessionDescription,type,beSilentOnLogs){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},Skylink.prototype._removeSDPFilteredCandidates=function(targetMid,sessionDescription){return"MCU"===targetMid&&sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER&&"firefox"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=sessionDescription.sdp.replace(/ generation 0/g,""),sessionDescription.sdp=sessionDescription.sdp.replace(/ udp /g," UDP ")),this._forceTURN&&this._hasMCU?(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not filtering ICE candidates as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured"]),sessionDescription.sdp):(this._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._filterCandidatesType.relay&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "relay" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*relay.*\r\n/g,"")),sessionDescription.sdp)},Skylink.prototype._getCodecsSupport=function(callback){var self=this;if(self._currentCodecSupport)return void callback(null);self._currentCodecSupport={audio:{},video:{}};try{if("edge"===window.webrtcDetectedBrowser){for(var codecs=RTCRtpSender.getCapabilities().codecs,i=0;i-1&&codecs[i].name){var codec=codecs[i].name.toLowerCase();self._currentCodecSupport[codecs[i].kind][codec]=codecs[i].clockRate+(codecs[i].numChannels>1?"/"+codecs[i].numChannels:"")}callback(null)}else{var pc=new RTCPeerConnection(null),offerConstraints={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveVideo:!0,OfferToReceiveAudio:!0}});try{var channel=pc.createDataChannel("test");self._binaryChunkType=channel.binaryType||self._binaryChunkType,self._binaryChunkType=self._binaryChunkType.toLowerCase().indexOf("array")>-1?self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER:self._binaryChunkType;for(var prop in self.DATA_TRANSFER_DATA_TYPE)if(self.DATA_TRANSFER_DATA_TYPE.hasOwnProperty(prop)&&self._binaryChunkType.toLowerCase()===self.DATA_TRANSFER_DATA_TYPE[prop].toLowerCase()){self._binaryChunkType=self.DATA_TRANSFER_DATA_TYPE[prop];break}}catch(e){}pc.createOffer(function(offer){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",i=0;i"],sdpLines[i]),self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE&&bundleLineIndex>-1&&0===mLineIndex&&("remote"===direction?sessionDescription.type===this.HANDSHAKE_PROGRESS.OFFER:sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER)){log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not removing rejected m="+mediaType+" line ->"],sdpLines[i]),settings.connection[mediaType]=!0,["audio","video"].indexOf(mediaType)>-1&&(settings.direction[mediaType].send=!1,settings.direction[mediaType].receive=!1);continue}if("edge"===window.webrtcDetectedBrowser){sdpLines.splice(i,1),i--;continue}if("remote"===direction||sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER){var parts=sdpLines[i].split(" ");parts[1]=0,sdpLines[i]=parts.join(" ");continue}}if("remote"!==direction||0!==sdpLines[i].indexOf("a=candidate:")||self.getPeerInfo(targetMid).config.enableIceTrickle||sdpLines[i+1]&&(0===sdpLines[i+1].indexOf("a=candidate:")||0===sdpLines[i+1].indexOf("a=end-of-candidates"))||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]),sdpLines.splice(i+1,0,"a=end-of-candidates"),i++),mediaType)if(settings.connection[mediaType]){if(0===sdpLines[i].indexOf("a=mid:"))bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||"");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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"undefined"!=typeof exports?module.exports={Skylink:Skylink,SkylinkLogs:SkylinkLogs}:globals?(globals.Skylink=Skylink,globals.SkylinkLogs=SkylinkLogs):window&&(window.Skylink=Skylink,window.SkylinkLogs=SkylinkLogs)}(this); \ No newline at end of file +;for(var key in obj)if(Object.prototype.hasOwnProperty.call(obj,key)&&_hasBinary(obj[key]))return!0}return!1}return _hasBinary(data)}var isArray=_dereq_("isarray");module.exports=hasBinary}).call(this,"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{})},{isarray:33}],30:[function(_dereq_,module,exports){(function(global){function hasBinary(data){function _hasBinary(obj){if(!obj)return!1;if(global.Buffer&&global.Buffer.isBuffer&&global.Buffer.isBuffer(obj)||global.ArrayBuffer&&obj instanceof ArrayBuffer||global.Blob&&obj instanceof Blob||global.File&&obj instanceof File)return!0;if(isArray(obj)){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;i=0)hasMatch=navigator.userAgent.match(/OPR\/(\d+)/i)||[],webrtcDetectedBrowser="opera",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=26,webrtcDetectedType="webkit",webrtcDetectedDCSupport="SCTP";else if(navigator.userAgent.match(/Bowser\/[0-9.]*/g)){hasMatch=navigator.userAgent.match(/Bowser\/[0-9.]*/g)||[];var chromiumVersion=parseInt((navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./i)||[])[2]||"0",10);webrtcDetectedBrowser="bowser",webrtcDetectedVersion=parseFloat((hasMatch[0]||"0/0").split("/")[1],10),webrtcMinimumVersion=0,webrtcDetectedType="webkit",webrtcDetectedDCSupport=chromiumVersion>30?"SCTP":"RTP"}else if(navigator.userAgent.indexOf("OPiOS")>0)hasMatch=navigator.userAgent.match(/OPiOS\/([0-9]+)\./),webrtcDetectedBrowser="opera",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=0,webrtcDetectedType=null,webrtcDetectedDCSupport=null;else if(navigator.userAgent.indexOf("CriOS")>0)hasMatch=navigator.userAgent.match(/CriOS\/([0-9]+)\./)||[],webrtcDetectedBrowser="chrome",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=0,webrtcDetectedType=null,webrtcDetectedDCSupport=null;else if(navigator.userAgent.indexOf("FxiOS")>0)hasMatch=navigator.userAgent.match(/FxiOS\/([0-9]+)\./)||[],webrtcDetectedBrowser="firefox",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=0,webrtcDetectedType=null,webrtcDetectedDCSupport=null;else if(document.documentMode)hasMatch=/\brv[ :]+(\d+)/g.exec(navigator.userAgent)||[],webrtcDetectedBrowser="IE",webrtcDetectedVersion=parseInt(hasMatch[1],10),webrtcMinimumVersion=9,webrtcDetectedType="plugin",webrtcDetectedDCSupport="SCTP",webrtcDetectedVersion||(hasMatch=/\bMSIE[ :]+(\d+)/g.exec(navigator.userAgent)||[],webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10));else if(window.StyleMedia||navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))hasMatch=navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)||[],webrtcDetectedBrowser="edge",webrtcDetectedVersion=parseFloat((hasMatch[0]||"0/0").split("/")[1],10),webrtcMinimumVersion=13.10547,webrtcDetectedType="ms",webrtcDetectedDCSupport=null;else if("undefined"!=typeof InstallTrigger||navigator.userAgent.indexOf("irefox")>0)hasMatch=navigator.userAgent.match(/Firefox\/([0-9]+)\./)||[],webrtcDetectedBrowser="firefox",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=33,webrtcDetectedType="moz",webrtcDetectedDCSupport="SCTP";else if(window.chrome&&window.chrome.webstore||navigator.userAgent.indexOf("Chrom")>0)hasMatch=navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./i)||[],webrtcDetectedBrowser="chrome",webrtcDetectedVersion=parseInt(hasMatch[2]||"0",10),webrtcMinimumVersion=38,webrtcDetectedType="webkit",webrtcDetectedDCSupport=webrtcDetectedVersion>30?"SCTP":"RTP";else if(/^((?!chrome|android).)*safari/i.test(navigator.userAgent)){hasMatch=navigator.userAgent.match(/version\/(\d+)/i)||[];var isMobile=navigator.userAgent.match(/(iPhone|iPad)/gi)||[];webrtcDetectedBrowser="safari",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=7,webrtcDetectedType=0===isMobile.length?"plugin":null,webrtcDetectedDCSupport=0===isMobile.length?"SCTP":null}window.webrtcDetectedBrowser=webrtcDetectedBrowser,window.webrtcDetectedVersion=webrtcDetectedVersion,window.webrtcMinimumVersion=webrtcMinimumVersion,window.webrtcDetectedType=webrtcDetectedType,window.webrtcDetectedDCSupport=webrtcDetectedDCSupport},AdapterJS.addEvent=function(elem,evnt,func){elem.addEventListener?elem.addEventListener(evnt,func,!1):elem.attachEvent?elem.attachEvent("on"+evnt,func):elem[evnt]=func},AdapterJS.renderNotificationBar=function(message,buttonText,buttonCallback){if("complete"===document.readyState){var w=window,i=document.createElement("iframe");i.name="adapterjs-alert",i.style.position="fixed",i.style.top="-41px",i.style.left=0,i.style.right=0,i.style.width="100%",i.style.height="40px",i.style.backgroundColor="#ffffe1",i.style.border="none",i.style.borderBottom="1px solid #888888",i.style.zIndex="9999999","string"==typeof i.style.webkitTransition?i.style.webkitTransition="all .5s ease-out":"string"==typeof i.style.transition&&(i.style.transition="all .5s ease-out"),document.body.appendChild(i);var c=i.contentWindow?i.contentWindow:i.contentDocument.document?i.contentDocument.document:i.contentDocument;c.document.open(),c.document.write(''+message+""),buttonText&&"function"==typeof buttonCallback?(c.document.write(''),c.document.close(),AdapterJS.addEvent(c.document.getElementById("okay"),"click",function(e){e.preventDefault();try{e.cancelBubble=!0}catch(error){}buttonCallback(e)}),AdapterJS.addEvent(c.document.getElementById("cancel"),"click",function(e){w.document.body.removeChild(i)})):c.document.close(),setTimeout(function(){"string"==typeof i.style.webkitTransform?i.style.webkitTransform="translateY(40px)":"string"==typeof i.style.transform?i.style.transform="translateY(40px)":i.style.top="0px"},300)}},webrtcDetectedType=null,checkMediaDataChannelSettings=function(peerBrowserAgent,peerBrowserVersion,callback,constraints){if("function"==typeof callback){var beOfferer=!0,isLocalFirefox="firefox"===webrtcDetectedBrowser,isLocalFirefoxInterop="moz"===webrtcDetectedType&&webrtcDetectedVersion>30,isPeerFirefox="firefox"===peerBrowserAgent;if(isLocalFirefox&&isPeerFirefox||isLocalFirefoxInterop)try{delete constraints.mandatory.MozDontOfferDataChannel}catch(error){console.error("Failed deleting MozDontOfferDataChannel"),console.error(error)}else isLocalFirefox&&!isPeerFirefox&&(constraints.mandatory.MozDontOfferDataChannel=!0);if(!isLocalFirefox)for(var prop in constraints.mandatory)constraints.mandatory.hasOwnProperty(prop)&&-1!==prop.indexOf("Moz")&&delete constraints.mandatory[prop];!isLocalFirefox||isPeerFirefox||isLocalFirefoxInterop||(beOfferer=!1),callback(beOfferer,constraints)}},checkIceConnectionState=function(peerId,iceConnectionState,callback){if("function"!=typeof callback)return void console.warn("No callback specified in checkIceConnectionState. Aborted.");peerId=peerId||"peer",AdapterJS._iceConnectionFiredStates[peerId]&&iceConnectionState!==AdapterJS._iceConnectionStates.disconnected&&iceConnectionState!==AdapterJS._iceConnectionStates.failed&&iceConnectionState!==AdapterJS._iceConnectionStates.closed||(AdapterJS._iceConnectionFiredStates[peerId]=[]),iceConnectionState=AdapterJS._iceConnectionStates[iceConnectionState],AdapterJS._iceConnectionFiredStates[peerId].indexOf(iceConnectionState)<0&&(AdapterJS._iceConnectionFiredStates[peerId].push(iceConnectionState),iceConnectionState===AdapterJS._iceConnectionStates.connected&&setTimeout(function(){AdapterJS._iceConnectionFiredStates[peerId].push(AdapterJS._iceConnectionStates.done),callback(AdapterJS._iceConnectionStates.done)},1e3),callback(iceConnectionState))},createIceServer=null,createIceServers=null,MediaStream="function"==typeof MediaStream?MediaStream:null,RTCPeerConnection="function"==typeof RTCPeerConnection?RTCPeerConnection:null,RTCSessionDescription="function"==typeof RTCSessionDescription?RTCSessionDescription:null,RTCIceCandidate="function"==typeof RTCIceCandidate?RTCIceCandidate:null,getUserMedia=null,attachMediaStream=null,reattachMediaStream=null,webrtcDetectedBrowser=null,webrtcDetectedVersion=null,webrtcMinimumVersion=null,!(navigator.mozGetUserMedia||navigator.webkitGetUserMedia||navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))||0===(navigator.userAgent.match(/android/gi)||[]).length&&0===(navigator.userAgent.match(/chrome/gi)||[]).length&&navigator.userAgent.indexOf("Safari/")>0?("object"==typeof console&&"function"==typeof console.log||(console={}||console,console.log=function(arg){},console.info=function(arg){},console.error=function(arg){},console.dir=function(arg){},console.exception=function(arg){},console.trace=function(arg){},console.warn=function(arg){},console.count=function(arg){},console.debug=function(arg){},console.count=function(arg){},console.time=function(arg){},console.timeEnd=function(arg){},console.group=function(arg){},console.groupCollapsed=function(arg){},console.groupEnd=function(arg){}),AdapterJS.parseWebrtcDetectedBrowser(),isIE="IE"===webrtcDetectedBrowser,AdapterJS.WebRTCPlugin.WaitForPluginReady=function(){for(;AdapterJS.WebRTCPlugin.pluginState!==AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY;);},AdapterJS.WebRTCPlugin.callWhenPluginReady=function(callback){if(AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY)callback();else var checkPluginReadyState=setInterval(function(){AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY&&(clearInterval(checkPluginReadyState),callback())},100)},AdapterJS.WebRTCPlugin.setLogLevel=function(logLevel){AdapterJS.WebRTCPlugin.callWhenPluginReady(function(){AdapterJS.WebRTCPlugin.plugin.setLogLevel(logLevel)})},AdapterJS.WebRTCPlugin.injectPlugin=function(){if("complete"===document.readyState&&AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING){if(AdapterJS.WebRTCPlugin.pluginState=AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTING,"IE"===webrtcDetectedBrowser&&webrtcDetectedVersion<=10){var frag=document.createDocumentFragment();for(AdapterJS.WebRTCPlugin.plugin=document.createElement("div"),AdapterJS.WebRTCPlugin.plugin.innerHTML=' '+(AdapterJS.options.getAllCams?'':"")+"";AdapterJS.WebRTCPlugin.plugin.firstChild;)frag.appendChild(AdapterJS.WebRTCPlugin.plugin.firstChild);document.body.appendChild(frag),AdapterJS.WebRTCPlugin.plugin=document.getElementById(AdapterJS.WebRTCPlugin.pluginInfo.pluginId)}else AdapterJS.WebRTCPlugin.plugin=document.createElement("object"),AdapterJS.WebRTCPlugin.plugin.id=AdapterJS.WebRTCPlugin.pluginInfo.pluginId,isIE?(AdapterJS.WebRTCPlugin.plugin.width="1px",AdapterJS.WebRTCPlugin.plugin.height="1px"):(AdapterJS.WebRTCPlugin.plugin.width="0px",AdapterJS.WebRTCPlugin.plugin.height="0px"),AdapterJS.WebRTCPlugin.plugin.type=AdapterJS.WebRTCPlugin.pluginInfo.type,AdapterJS.WebRTCPlugin.plugin.innerHTML=' '+(AdapterJS.options.getAllCams?'':"")+'',document.body.appendChild(AdapterJS.WebRTCPlugin.plugin);AdapterJS.WebRTCPlugin.pluginState=AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTED}},AdapterJS.WebRTCPlugin.isPluginInstalled=function(comName,plugName,plugType,installedCb,notInstalledCb){if(isIE){try{new ActiveXObject(comName+"."+plugName)}catch(e){return void notInstalledCb()}installedCb()}else{for(var pluginArray=navigator.mimeTypes,i=0;i=0)return void installedCb();notInstalledCb()}},AdapterJS.WebRTCPlugin.defineWebRTCInterface=function(){if(AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY)return void console.error("AdapterJS - WebRTC interface has already been defined");AdapterJS.WebRTCPlugin.pluginState=AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING,AdapterJS.isDefined=function(variable){return null!==variable&&void 0!==variable},createIceServer=function(url,username,password){var iceServer=null,urlParts=url.split(":");return 0===urlParts[0].indexOf("stun")?iceServer={url:url,hasCredentials:!1}:0===urlParts[0].indexOf("turn")&&(iceServer={url:url,hasCredentials:!0,credential:password,username:username}),iceServer},createIceServers=function(urls,username,password){for(var iceServers=[],i=0;i1)return iceServers&&(servers.iceServers=iceServers),AdapterJS.WebRTCPlugin.plugin.PeerConnection(servers);var mandatory=constraints&&constraints.mandatory?constraints.mandatory:null,optional=constraints&&constraints.optional?constraints.optional:null;return AdapterJS.WebRTCPlugin.plugin.PeerConnection(AdapterJS.WebRTCPlugin.pageId,iceServers,mandatory,optional)},MediaStreamTrack=function(){},MediaStreamTrack.getSources=function(callback){AdapterJS.WebRTCPlugin.callWhenPluginReady(function(){AdapterJS.WebRTCPlugin.plugin.GetSources(callback)})};var constraintsToPlugin=function(c){if("object"!=typeof c||c.mandatory||c.optional)return c;var cc={};return Object.keys(c).forEach(function(key){if("require"!==key&&"advanced"!==key&&"mediaSource"!==key){var r="object"==typeof c[key]?c[key]:{ideal:c[key]};void 0!==r.exact&&"number"==typeof r.exact&&(r.min=r.max=r.exact);var oldname=function(prefix,name){return prefix?prefix+name.charAt(0).toUpperCase()+name.slice(1):"deviceId"===name?"sourceId":name};if(void 0!==r.ideal){cc.optional=cc.optional||[];var oc={};"number"==typeof r.ideal?(oc[oldname("min",key)]=r.ideal,cc.optional.push(oc),oc={},oc[oldname("max",key)]=r.ideal,cc.optional.push(oc)):(oc[oldname("",key)]=r.ideal,cc.optional.push(oc))}void 0!==r.exact&&"number"!=typeof r.exact?(cc.mandatory=cc.mandatory||{},cc.mandatory[oldname("",key)]=r.exact):["min","max"].forEach(function(mix){void 0!==r[mix]&&(cc.mandatory=cc.mandatory||{},cc.mandatory[oldname(mix,key)]=r[mix])})}}),c.advanced&&(cc.optional=(cc.optional||[]).concat(c.advanced)),cc};getUserMedia=function(constraints,successCallback,failureCallback){var cc={};cc.audio=!!constraints.audio&&constraintsToPlugin(constraints.audio),cc.video=!!constraints.video&&constraintsToPlugin(constraints.video),AdapterJS.WebRTCPlugin.callWhenPluginReady(function(){AdapterJS.WebRTCPlugin.plugin.getUserMedia(cc,successCallback,failureCallback)})},window.navigator.getUserMedia=getUserMedia,navigator.mediaDevices||"undefined"==typeof Promise||(requestUserMedia=function(constraints){return new Promise(function(resolve,reject){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(){isIE||navigator.plugins.refresh(!1),AdapterJS.WebRTCPlugin.isPluginInstalled(AdapterJS.WebRTCPlugin.pluginInfo.prefix,AdapterJS.WebRTCPlugin.pluginInfo.plugName,AdapterJS.WebRTCPlugin.pluginInfo.type,function(){clearInterval(pluginInstallInterval),AdapterJS.WebRTCPlugin.defineWebRTCInterface()},function(){})},500)})}else AdapterJS.renderNotificationBar(AdapterJS.TEXT.PLUGIN.NOT_SUPPORTED)}},AdapterJS.WebRTCPlugin.isPluginInstalled(AdapterJS.WebRTCPlugin.pluginInfo.prefix,AdapterJS.WebRTCPlugin.pluginInfo.plugName,AdapterJS.WebRTCPlugin.pluginInfo.type,AdapterJS.WebRTCPlugin.defineWebRTCInterface,AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCb)):(!function(f){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=f();else if("function"==typeof define&&define.amd)define([],f);else{var g;g="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,g.adapter=f()}}(function(){return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n||e)},l,l.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o0?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&&(0===bandwidth[0].indexOf("b=TIAS:")?bandwidth=parseInt(bandwidth[0].substr(7),10):0===bandwidth[0].indexOf("b=AS:")&&(bandwidth=parseInt(bandwidth[0].substr(5),10)),encodingParameters.forEach(function(params){params.maxBitrate=bandwidth})),encodingParameters},SDPUtils.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.writeSessionBoilerplate=function(){return"v=0\r\no=thisisadapterortc 8169639915646943137 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n"},SDPUtils.writeMediaSection=function(transceiver,caps,type,stream){var sdp=SDPUtils.writeRtpDescription(transceiver.kind,caps);if(sdp+=SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters()),sdp+=SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(),"offer"===type?"actpass":"active"),sdp+="a=mid:"+transceiver.mid+"\r\n",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(selector,successCallback);var fixChromeStats_=function(response){var standardReport={};return response.result().forEach(function(report){var standardStats={id:report.id,timestamp:report.timestamp,type:report.type};report.names().forEach(function(name){standardStats[name]=report.stat(name)}),standardReport[standardStats.id]=standardStats}),standardReport},makeMapStats=function(stats,legacyStats){var map=new Map(Object.keys(stats).map(function(key){return[key,stats[key]]}));return legacyStats=legacyStats||stats,Object.keys(legacyStats).forEach(function(key){map[key]=legacyStats[key]}),map};if(arguments.length>=2){var successCallbackWrapper_=function(response){args[1](makeMapStats(fixChromeStats_(response)))};return origGetStats.apply(this,[successCallbackWrapper_,arguments[0]])}return new Promise(function(resolve,reject){1===args.length&&"object"==typeof selector?origGetStats.apply(self,[function(response){resolve(makeMapStats(fixChromeStats_(response)))},reject]):origGetStats.apply(self,[function(response){resolve(makeMapStats(fixChromeStats_(response),response.result()))},reject])}).then(successCallback,errorCallback)},pc},window.RTCPeerConnection.prototype=webkitRTCPeerConnection.prototype,webkitRTCPeerConnection.generateCertificate&&Object.defineProperty(window.RTCPeerConnection,"generateCertificate",{get:function(){return webkitRTCPeerConnection.generateCertificate}}),["createOffer","createAnswer"].forEach(function(method){var nativeMethod=webkitRTCPeerConnection.prototype[method];webkitRTCPeerConnection.prototype[method]=function(){var self=this;if(arguments.length<1||1===arguments.length&&"object"==typeof arguments[0]){var opts=1===arguments.length?arguments[0]:void 0;return new Promise(function(resolve,reject){nativeMethod.apply(self,[resolve,reject,opts])})}return nativeMethod.apply(this,arguments)}}),browserDetails.version<51&&["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach(function(method){var nativeMethod=webkitRTCPeerConnection.prototype[method];webkitRTCPeerConnection.prototype[method]=function(){var args=arguments,self=this,promise=new Promise(function(resolve,reject){nativeMethod.apply(self,[args[0],resolve,reject])});return args.length<2?promise:promise.then(function(){args[1].apply(null,[])},function(err){args.length>=3&&args[2].apply(null,[err])})}}),["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach(function(method){var nativeMethod=webkitRTCPeerConnection.prototype[method];webkitRTCPeerConnection.prototype[method]=function(){return arguments[0]=new("addIceCandidate"===method?RTCIceCandidate:RTCSessionDescription)(arguments[0]),nativeMethod.apply(this,arguments)}});var nativeAddIceCandidate=RTCPeerConnection.prototype.addIceCandidate;RTCPeerConnection.prototype.addIceCandidate=function(){return null===arguments[0]?Promise.resolve():nativeAddIceCandidate.apply(this,arguments)}}};module.exports={shimMediaStream:chromeShim.shimMediaStream,shimOnTrack:chromeShim.shimOnTrack,shimSourceObject:chromeShim.shimSourceObject,shimPeerConnection:chromeShim.shimPeerConnection,shimGetUserMedia:requirecopy("./getusermedia")}},{"../utils.js":10,"./getusermedia":4}],4:[function(requirecopy,module,exports){"use strict";var logging=requirecopy("../utils.js").log;module.exports=function(){var constraintsToChrome_=function(c){if("object"!=typeof c||c.mandatory||c.optional)return c;var cc={};return Object.keys(c).forEach(function(key){if("require"!==key&&"advanced"!==key&&"mediaSource"!==key){var r="object"==typeof c[key]?c[key]:{ideal:c[key]};void 0!==r.exact&&"number"==typeof r.exact&&(r.min=r.max=r.exact);var oldname_=function(prefix,name){return prefix?prefix+name.charAt(0).toUpperCase()+name.slice(1):"deviceId"===name?"sourceId":name};if(void 0!==r.ideal){cc.optional=cc.optional||[];var oc={};"number"==typeof r.ideal?(oc[oldname_("min",key)]=r.ideal,cc.optional.push(oc),oc={},oc[oldname_("max",key)]=r.ideal,cc.optional.push(oc)):(oc[oldname_("",key)]=r.ideal,cc.optional.push(oc))}void 0!==r.exact&&"number"!=typeof r.exact?(cc.mandatory=cc.mandatory||{},cc.mandatory[oldname_("",key)]=r.exact):["min","max"].forEach(function(mix){void 0!==r[mix]&&(cc.mandatory=cc.mandatory||{},cc.mandatory[oldname_(mix,key)]=r[mix])})}}),c.advanced&&(cc.optional=(cc.optional||[]).concat(c.advanced)),cc},shimConstraints_=function(constraints,func){if(constraints=JSON.parse(JSON.stringify(constraints)),constraints&&constraints.audio&&(constraints.audio=constraintsToChrome_(constraints.audio)),constraints&&"object"==typeof constraints.video){var face=constraints.video.facingMode;if((face=face&&("object"==typeof face?face:{ideal:face}))&&("user"===face.exact||"environment"===face.exact||"user"===face.ideal||"environment"===face.ideal)&&(!navigator.mediaDevices.getSupportedConstraints||!navigator.mediaDevices.getSupportedConstraints().facingMode)&&(delete constraints.video.facingMode,"environment"===face.exact||"environment"===face.ideal))return navigator.mediaDevices.enumerateDevices().then(function(devices){devices=devices.filter(function(d){return"videoinput"===d.kind});var back=devices.find(function(d){return-1!==d.label.toLowerCase().indexOf("back")})||devices.length&&devices[devices.length-1];return back&&(constraints.video.deviceId=face.exact?{exact:back.deviceId}:{ideal:back.deviceId}),constraints.video=constraintsToChrome_(constraints.video),logging("chrome: "+JSON.stringify(constraints)),func(constraints)});constraints.video=constraintsToChrome_(constraints.video)}return logging("chrome: "+JSON.stringify(constraints)),func(constraints)},shimError_=function(e){return{name:{PermissionDeniedError:"NotAllowedError",ConstraintNotSatisfiedError:"OverconstrainedError"}[e.name]||e.name,message:e.message,constraint:e.constraintName,toString:function(){return this.name+(this.message&&": ")+this.message}}},getUserMedia_=function(constraints,onSuccess,onError){shimConstraints_(constraints,function(c){navigator.webkitGetUserMedia(c,onSuccess,function(e){onError(shimError_(e))})})};navigator.getUserMedia=getUserMedia_;var getUserMediaPromise_=function(constraints){return new Promise(function(resolve,reject){navigator.getUserMedia(constraints,resolve,reject)})};if(navigator.mediaDevices||(navigator.mediaDevices={getUserMedia:getUserMediaPromise_,enumerateDevices:function(){return new Promise(function(resolve){var kinds={audio:"audioinput",video:"videoinput"};return MediaStreamTrack.getSources(function(devices){resolve(devices.map(function(device){return{label:device.label,kind:kinds[device.kind],deviceId:device.id,groupId:""}}))})})}}),navigator.mediaDevices.getUserMedia){var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(cs){return shimConstraints_(cs,function(c){return origGetUserMedia(c).catch(function(e){return Promise.reject(shimError_(e))})})}}else navigator.mediaDevices.getUserMedia=function(constraints){return getUserMediaPromise_(constraints)};void 0===navigator.mediaDevices.addEventListener&&(navigator.mediaDevices.addEventListener=function(){logging("Dummy mediaDevices.addEventListener called.")}),void 0===navigator.mediaDevices.removeEventListener&&(navigator.mediaDevices.removeEventListener=function(){logging("Dummy mediaDevices.removeEventListener called.")})}},{"../utils.js":10}],5:[function(requirecopy,module,exports){"use strict";var SDPUtils=requirecopy("sdp"),browserDetails=requirecopy("../utils").browserDetails,edgeShim={shimPeerConnection:function(){window.RTCIceGatherer&&(window.RTCIceCandidate||(window.RTCIceCandidate=function(args){return args}),window.RTCSessionDescription||(window.RTCSessionDescription=function(args){return args})),window.RTCPeerConnection=function(config){var self=this,_eventTarget=document.createDocumentFragment();if(["addEventListener","removeEventListener","dispatchEvent"].forEach(function(method){self[method]=_eventTarget[method].bind(_eventTarget)}),this.onicecandidate=null,this.onaddstream=null,this.ontrack=null,this.onremovestream=null,this.onsignalingstatechange=null,this.oniceconnectionstatechange=null,this.onnegotiationneeded=null,this.ondatachannel=null,this.localStreams=[],this.remoteStreams=[],this.getLocalStreams=function(){return self.localStreams},this.getRemoteStreams=function(){return self.remoteStreams},this.localDescription=new RTCSessionDescription({type:"",sdp:""}),this.remoteDescription=new RTCSessionDescription({type:"",sdp:""}),this.signalingState="stable",this.iceConnectionState="new",this.iceGatheringState="new",this.iceOptions={gatherPolicy:"all",iceServers:[]},config&&config.iceTransportPolicy)switch(config.iceTransportPolicy){case"all":case"relay":this.iceOptions.gatherPolicy=config.iceTransportPolicy;break;case"none":throw new TypeError('iceTransportPolicy "none" not supported')}if(this.usingBundle=config&&"max-bundle"===config.bundlePolicy,config&&config.iceServers){var iceServers=JSON.parse(JSON.stringify(config.iceServers));this.iceOptions.iceServers=iceServers.filter(function(server){if(server&&server.urls){var urls=server.urls;return"string"==typeof urls&&(urls=[urls]),!!(urls=urls.filter(function(url){return 0===url.indexOf("turn:")&&-1!==url.indexOf("transport=udp")&&-1===url.indexOf("turn:[")||0===url.indexOf("stun:")&&browserDetails.version>=14393})[0])}return!1})}this.transceivers=[],this._localIceCandidatesBuffer=[]},window.RTCPeerConnection.prototype._emitBufferedCandidates=function(){var self=this,sections=SDPUtils.splitSections(self.localDescription.sdp);this._localIceCandidatesBuffer.forEach(function(event){if(event.candidate&&0!==Object.keys(event.candidate).length)-1===event.candidate.candidate.indexOf("typ endOfCandidates")&&(sections[event.candidate.sdpMLineIndex+1]+="a="+event.candidate.candidate+"\r\n");else for(var j=1;j-1&&(this.localStreams.splice(idx,1),this._maybeFireNegotiationNeeded())},window.RTCPeerConnection.prototype.getSenders=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpSender}).map(function(transceiver){return transceiver.rtpSender})},window.RTCPeerConnection.prototype.getReceivers=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpReceiver}).map(function(transceiver){return transceiver.rtpReceiver})},window.RTCPeerConnection.prototype._getCommonCapabilities=function(localCapabilities,remoteCapabilities){var commonCapabilities={codecs:[],headerExtensions:[],fecMechanisms:[]};return localCapabilities.codecs.forEach(function(lCodec){for(var i=0;i0;sections.forEach(function(mediaSection,sdpMLineIndex){var transceiver=self.transceivers[sdpMLineIndex],iceGatherer=transceiver.iceGatherer,iceTransport=transceiver.iceTransport,dtlsTransport=transceiver.dtlsTransport,localCapabilities=transceiver.localCapabilities,remoteCapabilities=transceiver.remoteCapabilities;if("0"!==mediaSection.split("\n",1)[0].split(" ",2)[1]&&!transceiver.isDatachannel){var remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);if(isIceLite){var cands=SDPUtils.matchPrefix(mediaSection,"a=candidate:").map(function(cand){return SDPUtils.parseCandidate(cand)}).filter(function(cand){return"1"===cand.component});cands.length&&iceTransport.setRemoteCandidates(cands)}var remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);isIceLite&&(remoteDtlsParameters.role="server"),self.usingBundle&&0!==sdpMLineIndex||(iceTransport.start(iceGatherer,remoteIceParameters,isIceLite?"controlling":"controlled"),dtlsTransport.start(remoteDtlsParameters));var params=self._getCommonCapabilities(localCapabilities,remoteCapabilities);self._transceive(transceiver,params.codecs.length>0,!1)}})}switch(this.localDescription={type:description.type,sdp:description.sdp},description.type){case"offer":this._updateSignalingState("have-local-offer");break;case"answer":this._updateSignalingState("stable");break;default:throw new TypeError('unsupported type "'+description.type+'"')}var hasCallback=arguments.length>1&&"function"==typeof arguments[1];if(hasCallback){var cb=arguments[1];window.setTimeout(function(){cb(),"new"===self.iceGatheringState&&(self.iceGatheringState="gathering"),self._emitBufferedCandidates()},0)}var p=Promise.resolve();return p.then(function(){hasCallback||("new"===self.iceGatheringState&&(self.iceGatheringState="gathering"),window.setTimeout(self._emitBufferedCandidates.bind(self),500))}),p},window.RTCPeerConnection.prototype.setRemoteDescription=function(description){var self=this,stream=new MediaStream,receiverList=[],sections=SDPUtils.splitSections(description.sdp),sessionpart=sections.shift(),isIceLite=SDPUtils.matchPrefix(sessionpart,"a=ice-lite").length>0;switch(this.usingBundle=SDPUtils.matchPrefix(sessionpart,"a=group:BUNDLE ").length>0,sections.forEach(function(mediaSection,sdpMLineIndex){var lines=SDPUtils.splitLines(mediaSection),mline=lines[0].substr(2).split(" "),kind=mline[0],rejected="0"===mline[1],direction=SDPUtils.getDirection(mediaSection,sessionpart),mid=SDPUtils.matchPrefix(mediaSection,"a=mid:");if(mid=mid.length?mid[0].substr(6):SDPUtils.generateIdentifier(),"application"===kind&&"DTLS/SCTP"===mline[2])return void(self.transceivers[sdpMLineIndex]={mid:mid,isDatachannel:!0});var transceiver,iceGatherer,iceTransport,dtlsTransport,rtpSender,rtpReceiver,sendEncodingParameters,recvEncodingParameters,localCapabilities,track,remoteIceParameters,remoteDtlsParameters,remoteCapabilities=SDPUtils.parseRtpParameters(mediaSection);rejected||(remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart),remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart),remoteDtlsParameters.role="client"),recvEncodingParameters=SDPUtils.parseRtpEncodingParameters(mediaSection);var cname,remoteSsrc=SDPUtils.matchPrefix(mediaSection,"a=ssrc:").map(function(line){return SDPUtils.parseSsrcMedia(line)}).filter(function(obj){return"cname"===obj.attribute})[0];remoteSsrc&&(cname=remoteSsrc.value);var isComplete=SDPUtils.matchPrefix(mediaSection,"a=end-of-candidates",sessionpart).length>0,cands=SDPUtils.matchPrefix(mediaSection,"a=candidate:").map(function(cand){return SDPUtils.parseCandidate(cand)}).filter(function(cand){return"1"===cand.component});if("offer"!==description.type||rejected)"answer"!==description.type||rejected||(transceiver=self.transceivers[sdpMLineIndex],iceGatherer=transceiver.iceGatherer,iceTransport=transceiver.iceTransport,dtlsTransport=transceiver.dtlsTransport,rtpSender=transceiver.rtpSender,rtpReceiver=transceiver.rtpReceiver,sendEncodingParameters=transceiver.sendEncodingParameters,localCapabilities=transceiver.localCapabilities,self.transceivers[sdpMLineIndex].recvEncodingParameters=recvEncodingParameters,self.transceivers[sdpMLineIndex].remoteCapabilities=remoteCapabilities,self.transceivers[sdpMLineIndex].cname=cname,(isIceLite||isComplete)&&cands.length&&iceTransport.setRemoteCandidates(cands),self.usingBundle&&0!==sdpMLineIndex||(iceTransport.start(iceGatherer,remoteIceParameters,"controlling"),dtlsTransport.start(remoteDtlsParameters)),self._transceive(transceiver,"sendrecv"===direction||"recvonly"===direction,"sendrecv"===direction||"sendonly"===direction),!rtpReceiver||"sendrecv"!==direction&&"sendonly"!==direction?delete transceiver.rtpReceiver:(track=rtpReceiver.track,receiverList.push([track,rtpReceiver]),stream.addTrack(track)));else{var transports=self.usingBundle&&sdpMLineIndex>0?{iceGatherer:self.transceivers[0].iceGatherer,iceTransport:self.transceivers[0].iceTransport,dtlsTransport:self.transceivers[0].dtlsTransport}:self._createIceAndDtlsTransports(mid,sdpMLineIndex);if(isComplete&&transports.iceTransport.setRemoteCandidates(cands),localCapabilities=RTCRtpReceiver.getCapabilities(kind),sendEncodingParameters=[{ssrc:1001*(2*sdpMLineIndex+2)}],rtpReceiver=new RTCRtpReceiver(transports.dtlsTransport,kind),track=rtpReceiver.track,receiverList.push([track,rtpReceiver]),stream.addTrack(track),self.localStreams.length>0&&self.localStreams[0].getTracks().length>=sdpMLineIndex){var localTrack;"audio"===kind?localTrack=self.localStreams[0].getAudioTracks()[0]:"video"===kind&&(localTrack=self.localStreams[0].getVideoTracks()[0]),localTrack&&(rtpSender=new RTCRtpSender(localTrack,transports.dtlsTransport))}self.transceivers[sdpMLineIndex]={iceGatherer:transports.iceGatherer,iceTransport:transports.iceTransport,dtlsTransport:transports.dtlsTransport,localCapabilities:localCapabilities,remoteCapabilities:remoteCapabilities,rtpSender:rtpSender,rtpReceiver:rtpReceiver,kind:kind,mid:mid,cname:cname,sendEncodingParameters:sendEncodingParameters,recvEncodingParameters:recvEncodingParameters},self._transceive(self.transceivers[sdpMLineIndex],!1,"sendrecv"===direction||"sendonly"===direction)}}),this.remoteDescription={type:description.type,sdp:description.sdp},description.type){case"offer":this._updateSignalingState("have-remote-offer");break;case"answer":this._updateSignalingState("stable");break;default:throw new TypeError('unsupported type "'+description.type+'"')}return stream.getTracks().length&&(self.remoteStreams.push(stream),window.setTimeout(function(){var event=new Event("addstream");event.stream=stream,self.dispatchEvent(event),null!==self.onaddstream&&window.setTimeout(function(){self.onaddstream(event)},0),receiverList.forEach(function(item){var track=item[0],receiver=item[1],trackEvent=new Event("track");trackEvent.track=track,trackEvent.receiver=receiver,trackEvent.streams=[stream],self.dispatchEvent(event),null!==self.ontrack&&window.setTimeout(function(){self.ontrack(trackEvent)},0)})},0)),arguments.length>1&&"function"==typeof arguments[1]&&window.setTimeout(arguments[1],0),Promise.resolve()},window.RTCPeerConnection.prototype.close=function(){this.transceivers.forEach(function(transceiver){transceiver.iceTransport&&transceiver.iceTransport.stop(),transceiver.dtlsTransport&&transceiver.dtlsTransport.stop(),transceiver.rtpSender&&transceiver.rtpSender.stop(),transceiver.rtpReceiver&&transceiver.rtpReceiver.stop()}),this._updateSignalingState("closed")},window.RTCPeerConnection.prototype._updateSignalingState=function(newState){this.signalingState=newState;var event=new Event("signalingstatechange");this.dispatchEvent(event),null!==this.onsignalingstatechange&&this.onsignalingstatechange(event)},window.RTCPeerConnection.prototype._maybeFireNegotiationNeeded=function(){var event=new Event("negotiationneeded");this.dispatchEvent(event),null!==this.onnegotiationneeded&&this.onnegotiationneeded(event)},window.RTCPeerConnection.prototype._updateConnectionState=function(){var newState,self=this,states={new:0,closed:0,connecting:0,checking:0,connected:0,completed:0,failed:0};if(this.transceivers.forEach(function(transceiver){states[transceiver.iceTransport.state]++,states[transceiver.dtlsTransport.state]++}),states.connected+=states.completed,newState="new",states.failed>0?newState="failed":states.connecting>0||states.checking>0?newState="connecting":states.disconnected>0?newState="disconnected":states.new>0?newState="new":(states.connected>0||states.completed>0)&&(newState="connected"),newState!==self.iceConnectionState){self.iceConnectionState=newState;var event=new Event("iceconnectionstatechange");this.dispatchEvent(event),null!==this.oniceconnectionstatechange&&this.oniceconnectionstatechange(event)}},window.RTCPeerConnection.prototype.createOffer=function(){var self=this;if(this._pendingOffer)throw new Error("createOffer called while there is a pending offer.");var offerOptions +;1===arguments.length&&"function"!=typeof arguments[0]?offerOptions=arguments[0]:3===arguments.length&&(offerOptions=arguments[2]);var tracks=[],numAudioTracks=0,numVideoTracks=0;if(this.localStreams.length&&(numAudioTracks=this.localStreams[0].getAudioTracks().length,numVideoTracks=this.localStreams[0].getVideoTracks().length),offerOptions){if(offerOptions.mandatory||offerOptions.optional)throw new TypeError("Legacy mandatory/optional constraints not supported.");void 0!==offerOptions.offerToReceiveAudio&&(numAudioTracks=offerOptions.offerToReceiveAudio),void 0!==offerOptions.offerToReceiveVideo&&(numVideoTracks=offerOptions.offerToReceiveVideo)}for(this.localStreams.length&&this.localStreams[0].getTracks().forEach(function(track){tracks.push({kind:track.kind,track:track,wantReceive:"audio"===track.kind?numAudioTracks>0:numVideoTracks>0}),"audio"===track.kind?numAudioTracks--:"video"===track.kind&&numVideoTracks--});numAudioTracks>0||numVideoTracks>0;)numAudioTracks>0&&(tracks.push({kind:"audio",wantReceive:!0}),numAudioTracks--),numVideoTracks>0&&(tracks.push({kind:"video",wantReceive:!0}),numVideoTracks--);var sdp=SDPUtils.writeSessionBoilerplate(),transceivers=[];tracks.forEach(function(mline,sdpMLineIndex){var rtpSender,rtpReceiver,track=mline.track,kind=mline.kind,mid=SDPUtils.generateIdentifier(),transports=self.usingBundle&&sdpMLineIndex>0?{iceGatherer:transceivers[0].iceGatherer,iceTransport:transceivers[0].iceTransport,dtlsTransport:transceivers[0].dtlsTransport}:self._createIceAndDtlsTransports(mid,sdpMLineIndex),localCapabilities=RTCRtpSender.getCapabilities(kind),sendEncodingParameters=[{ssrc:1001*(2*sdpMLineIndex+1)}];track&&(rtpSender=new RTCRtpSender(track,transports.dtlsTransport)),mline.wantReceive&&(rtpReceiver=new RTCRtpReceiver(transports.dtlsTransport,kind)),transceivers[sdpMLineIndex]={iceGatherer:transports.iceGatherer,iceTransport:transports.iceTransport,dtlsTransport:transports.dtlsTransport,localCapabilities:localCapabilities,remoteCapabilities:null,rtpSender:rtpSender,rtpReceiver:rtpReceiver,kind:kind,mid:mid,sendEncodingParameters:sendEncodingParameters,recvEncodingParameters:null}}),this.usingBundle&&(sdp+="a=group:BUNDLE "+transceivers.map(function(t){return t.mid}).join(" ")+"\r\n"),tracks.forEach(function(mline,sdpMLineIndex){var transceiver=transceivers[sdpMLineIndex];sdp+=SDPUtils.writeMediaSection(transceiver,transceiver.localCapabilities,"offer",self.localStreams[0])}),this._pendingOffer=transceivers;var desc=new RTCSessionDescription({type:"offer",sdp:sdp});return arguments.length&&"function"==typeof arguments[0]&&window.setTimeout(arguments[0],0,desc),Promise.resolve(desc)},window.RTCPeerConnection.prototype.createAnswer=function(){var self=this,sdp=SDPUtils.writeSessionBoilerplate();this.usingBundle&&(sdp+="a=group:BUNDLE "+this.transceivers.map(function(t){return t.mid}).join(" ")+"\r\n"),this.transceivers.forEach(function(transceiver){if(transceiver.isDatachannel)return void(sdp+="m=application 0 DTLS/SCTP 5000\r\nc=IN IP4 0.0.0.0\r\na=mid:"+transceiver.mid+"\r\n");var commonCapabilities=self._getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);sdp+=SDPUtils.writeMediaSection(transceiver,commonCapabilities,"answer",self.localStreams[0])});var desc=new RTCSessionDescription({type:"answer",sdp:sdp});return arguments.length&&"function"==typeof arguments[0]&&window.setTimeout(arguments[0],0,desc),Promise.resolve(desc)},window.RTCPeerConnection.prototype.addIceCandidate=function(candidate){if(null===candidate)this.transceivers.forEach(function(transceiver){transceiver.iceTransport.addRemoteCandidate({})});else{var mLineIndex=candidate.sdpMLineIndex;if(candidate.sdpMid)for(var i=0;i0?SDPUtils.parseCandidate(candidate.candidate):{};if("tcp"===cand.protocol&&(0===cand.port||9===cand.port))return;if("1"!==cand.component)return;"endOfCandidates"===cand.type&&(cand={}),transceiver.iceTransport.addRemoteCandidate(cand);var sections=SDPUtils.splitSections(this.remoteDescription.sdp);sections[mLineIndex+1]+=(cand.type?candidate.candidate.trim():"a=end-of-candidates")+"\r\n",this.remoteDescription.sdp=sections.join("")}}return arguments.length>1&&"function"==typeof arguments[1]&&window.setTimeout(arguments[1],0),Promise.resolve()},window.RTCPeerConnection.prototype.getStats=function(){var promises=[];this.transceivers.forEach(function(transceiver){["rtpSender","rtpReceiver","iceGatherer","iceTransport","dtlsTransport"].forEach(function(method){transceiver[method]&&promises.push(transceiver[method].getStats())})});var cb=arguments.length>1&&"function"==typeof arguments[1]&&arguments[1];return new Promise(function(resolve){var results=new Map;Promise.all(promises).then(function(res){res.forEach(function(result){Object.keys(result).forEach(function(id){results.set(id,result[id]),results[id]=result[id]})}),cb&&window.setTimeout(cb,0,results),resolve(results)})})}}};module.exports={shimPeerConnection:edgeShim.shimPeerConnection,shimGetUserMedia:requirecopy("./getusermedia")}},{"../utils":10,"./getusermedia":6,sdp:1}],6:[function(requirecopy,module,exports){"use strict";module.exports=function(){var shimError_=function(e){return{name:{PermissionDeniedError:"NotAllowedError"}[e.name]||e.name,message:e.message,constraint:e.constraint,toString:function(){return this.name}}},origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(c){return origGetUserMedia(c).catch(function(e){return Promise.reject(shimError_(e))})}}},{}],7:[function(requirecopy,module,exports){"use strict";var browserDetails=requirecopy("../utils").browserDetails,firefoxShim={shimOnTrack:function(){"object"!=typeof window||!window.RTCPeerConnection||"ontrack"in window.RTCPeerConnection.prototype||Object.defineProperty(window.RTCPeerConnection.prototype,"ontrack",{get:function(){return this._ontrack},set:function(f){this._ontrack&&(this.removeEventListener("track",this._ontrack),this.removeEventListener("addstream",this._ontrackpoly)),this.addEventListener("track",this._ontrack=f),this.addEventListener("addstream",this._ontrackpoly=function(e){e.stream.getTracks().forEach(function(track){var event=new Event("track");event.track=track,event.receiver={track:track},event.streams=[e.stream],this.dispatchEvent(event)}.bind(this))}.bind(this))}})},shimSourceObject:function(){"object"==typeof window&&(!window.HTMLMediaElement||"srcObject"in window.HTMLMediaElement.prototype||Object.defineProperty(window.HTMLMediaElement.prototype,"srcObject",{get:function(){return this.mozSrcObject},set:function(stream){this.mozSrcObject=stream}}))},shimPeerConnection:function(){if("object"==typeof window&&(window.RTCPeerConnection||window.mozRTCPeerConnection)){window.RTCPeerConnection||(window.RTCPeerConnection=function(pcConfig,pcConstraints){if(browserDetails.version<38&&pcConfig&&pcConfig.iceServers){for(var newIceServers=[],i=0;i=pos&&parseInt(match[pos],10)},detectBrowser:function(){var result={};if(result.browser=null,result.version=null,"undefined"==typeof window||!window.navigator)return result.browser="Not a browser.",result;if(navigator.mozGetUserMedia)result.browser="firefox",result.version=this.extractVersion(navigator.userAgent,/Firefox\/([0-9]+)\./,1);else if(navigator.webkitGetUserMedia)if(window.webkitRTCPeerConnection)result.browser="chrome",result.version=this.extractVersion(navigator.userAgent,/Chrom(e|ium)\/([0-9]+)\./,2);else{if(!navigator.userAgent.match(/Version\/(\d+).(\d+)/))return result.browser="Unsupported webkit-based browser with GUM support but no WebRTC support.",result;result.browser="safari",result.version=this.extractVersion(navigator.userAgent,/AppleWebKit\/([0-9]+)\./,1)}else{if(!navigator.mediaDevices||!navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))return result.browser="Not a supported browser.",result;result.browser="edge",result.version=this.extractVersion(navigator.userAgent,/Edge\/(\d+).(\d+)$/,2)}return result}};module.exports={log:utils.log,disableLog:utils.disableLog,browserDetails:utils.detectBrowser(),extractVersion:utils.extractVersion}},{}]},{},[2])(2)}),AdapterJS.parseWebrtcDetectedBrowser(),navigator.mozGetUserMedia?(MediaStreamTrack.getSources=function(successCb){setTimeout(function(){successCb([{kind:"audio",id:"default",label:"",facing:""},{kind:"video",id:"default",label:"",facing:""}])},0)},attachMediaStream=function(element,stream){return element.srcObject=stream,element},reattachMediaStream=function(to,from){return to.srcObject=from.srcObject,to},createIceServer=function(url,username,password){console.warn("createIceServer is deprecated. It should be replaced with an application level implementation.");var iceServer=null,urlParts=url.split(":");if(0===urlParts[0].indexOf("stun"))iceServer={urls:[url]};else if(0===urlParts[0].indexOf("turn"))if(webrtcDetectedVersion<27){var turnUrlParts=url.split("?");1!==turnUrlParts.length&&0!==turnUrlParts[1].indexOf("transport=udp")||(iceServer={urls:[turnUrlParts[0]],credential:password,username:username})}else iceServer={urls:[url],credential:password,username:username};return iceServer},createIceServers=function(urls,username,password){console.warn("createIceServers is deprecated. It should be replaced with an application level implementation.");var iceServers=[];for(i=0;i=43?element.srcObject=stream:void 0!==element.src?element.src=URL.createObjectURL(stream):console.error("Error attaching stream to element."),element},reattachMediaStream=function(to,from){return webrtcDetectedVersion>=43?to.srcObject=from.srcObject:to.src=from.src,to},createIceServer=function(url,username,password){console.warn("createIceServer is deprecated. It should be replaced with an application level implementation.");var iceServer=null,urlParts=url.split(":");return 0===urlParts[0].indexOf("stun")?iceServer={url:url}:0===urlParts[0].indexOf("turn")&&(iceServer={url:url,credential:password,username:username}),iceServer},createIceServers=function(urls,username,password){console.warn("createIceServers is deprecated. It should be replaced with an application level implementation.");var iceServers=[];if(webrtcDetectedVersion>=34)iceServers={urls:urls,credential:password,username:username};else for(i=0;i38?element.srcObject=stream:void 0!==element.src&&(element.src=URL.createObjectURL(stream))}),attachMediaStream=function(element,stream){return"chrome"!==webrtcDetectedBrowser&&"opera"!==webrtcDetectedBrowser||stream?attachMediaStream_base(element,stream):element.src="",element},reattachMediaStream_base=reattachMediaStream,reattachMediaStream=function(to,from){return reattachMediaStream_base(to,from),to},window.attachMediaStream=attachMediaStream,window.reattachMediaStream=reattachMediaStream,window.getUserMedia=function(constraints,onSuccess,onFailure){navigator.getUserMedia(constraints,onSuccess,onFailure)},AdapterJS.attachMediaStream=attachMediaStream,AdapterJS.reattachMediaStream=reattachMediaStream,AdapterJS.getUserMedia=getUserMedia,"undefined"==typeof Promise&&(requestUserMedia=null),AdapterJS.maybeThroughWebRTCReady()),"undefined"!=typeof exports&&(module.exports=AdapterJS),AdapterJS.TEXT.EXTENSION={REQUIRE_INSTALLATION_FF:"To enable screensharing you need to install the Skylink WebRTC tools Firefox Add-on.",REQUIRE_INSTALLATION_CHROME:"To enable screensharing you need to install the Skylink WebRTC tools Chrome Extension.",REQUIRE_REFRESH:"Please refresh this page after the Skylink WebRTC tools extension has been installed.",BUTTON_FF:"Install Now",BUTTON_CHROME:"Go to Chrome Web Store"},AdapterJS.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(window.navigator.mozGetUserMedia)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&&window.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(window.navigator.webkitGetUserMedia&&"safari"!==window.webrtcDetectedBrowser){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"===window.webrtcDetectedBrowser?!!AdapterJS.extensionInfo.opera.extensionId:"chrome"===window.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"!==window.webrtcDetectedBrowser)iframe.getSourceId(updatedConstraints.video.mediaSource,fetchStream);else{var extensionId=AdapterJS.extensionInfo["opera"===window.webrtcDetectedBrowser?"opera":"chrome"].extensionId,extensionLink=AdapterJS.extensionInfo["opera"===window.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"===window.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 navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)?console.warn("Edge does not support screensharing feature in getUserMedia"):(baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(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"));var sourceId=AdapterJS.WebRTCPlugin.plugin.screensharingKey||"Screensharing";if(AdapterJS.WebRTCPlugin.plugin.screensharingKeys)if(Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("screen")>-1&&updatedConstraints.video.mediaSource.indexOf("window")>-1)sourceId=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)sourceId=AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screen,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'));sourceId=AdapterJS.WebRTCPlugin.plugin.screensharingKeys.window,updatedConstraints.video.mediaSource=AdapterJS.WebRTCPlugin.plugin.screensharingKeys.window}updatedConstraints.video.optional=updatedConstraints.video.optional||[],updatedConstraints.video.optional.push({sourceId:sourceId}),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._isUsingPlugin=!1,this._TURNTransport="any",this._peerInformations={},this._user=null,this._userData="",this._peerPriorityWeight=0,this._autoIntroduce=!0,this._isPrivileged=!1,this._peerList=null,this._selectedRoom=null,this._roomLocked=!1,this._inRoom=!1,this._EVENTS={},this._onceEvents={},this._timestamp={socketMessage:null,shareScreen:null,refreshConnection:null,getUserMedia:null,lastRestart:null},this._throttlingTimeouts={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},this._throttlingShouldThrowError=!1,this._socketSession={},this._socketMessageQueue=[],this._socketMessageTimeout=null,this._socketPorts={"http:":[80,3e3],"https:":[443,3443]},this._channelOpen=!1,this._signalingServer=null,this._signalingServerProtocol=window.location.protocol,this._signalingServerPort=null,this._socket=null,this._socketTimeout=2e4,this._socketUseXDR=!1,this._enableIceRestart="firefox"!==window.webrtcDetectedBrowser||window.webrtcDetectedVersion>=48,this._hasMCU=!1,this._forceSSL=!1,this._forceTURNSSL=!1,this._forceTURN=!1,this._path=null,this._roomServer="//api.temasys.io",this._appKey=null,this._defaultRoom=null,this._roomStart=null,this._roomDuration=null,this._roomCredentials=null,this._readyState=0,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._audioFallback=!1,this._streams={userMedia:null,screenshare:null},this._streamsDefaultSettings={userMedia:{audio:{stereo:!1},video:{resolution:{width:640,height:480},frameRate:50}},screenshare:{video:!0}},this._streamsMutedSettings={audioMuted:!1,videoMuted:!1},this._streamsBandwidthSettings={googleX:{},bAS:{}},this._streamsStoppedCbs={},this._streamsSession={},this._selectedAudioCodec="auto",this._selectedVideoCodec="auto",this._disableVideoFecCodecs=!1,this._disableComfortNoiseCodec=!1,this._disableREMB=!1,this._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},this._publishOnly=!1,this._parentId=null,this._recordings={},this._currentRecordingId=!1,this._recordingStartInterval=null,this._mcuUseRenegoRestart=!1,this._iceServer=null,this._socketServer=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType="firefox"===window.webrtcDetectedBrowser?this.DATA_TRANSFER_DATA_TYPE.BLOB:this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={},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;var clone=function(obj){if(null===obj||"object"!=typeof obj)return obj;var copy=function(data){var copy=data.constructor();for(var attr in data)data.hasOwnProperty(attr)&&(copy[attr]=data[attr]);return copy};if("object"==typeof obj&&!Array.isArray(obj))try{return JSON.parse(JSON.stringify(obj))}catch(err){return copy(obj)}return copy(obj)};Skylink.prototype.DATA_CHANNEL_STATE={CONNECTING:"connecting",OPEN:"open",CLOSING:"closing",CLOSED:"closed",ERROR:"error",CREATE_ERROR:"createError",BUFFERED_AMOUNT_LOW:"bufferedAmountLow",SEND_MESSAGE_ERROR:"sendMessageError"},Skylink.prototype.DATA_CHANNEL_TYPE={MESSAGING:"messaging",DATA:"data"},Skylink.prototype.DATA_CHANNEL_MESSAGE_ERROR={MESSAGE:"message",TRANSFER:"transfer"},Skylink.prototype._createDataChannel=function(peerId,dataChannel,bufferThreshold,createAsMessagingChannel){var self=this,channelName=(self._user&&self._user.sid?self._user.sid:"-")+"_"+peerId,channelType=createAsMessagingChannel?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,channelProp=channelType===self.DATA_CHANNEL_TYPE.MESSAGING?"main":channelName;if(!self._user)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as User does not have Room session"]);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as Peer connection does not exists"]);if(dataChannel&&"object"==typeof dataChannel?channelName=dataChannel.label:"string"==typeof dataChannel&&(channelName=dataChannel,dataChannel=null),!dataChannel)try{dataChannel=self._peerConnections[peerId].createDataChannel(channelName,{reliable:!0,ordered:!0})}catch(error){return log.error([peerId,"RTCDataChannel",channelProp,"Failed creating Datachannel ->"],error),void self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CREATE_ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))}self._dataChannels[peerId]?self._dataChannels[peerId].main&&self._dataChannels[peerId].main.channel.label===channelName&&(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING):(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING,self._dataChannels[peerId]={},log.debug([peerId,"RTCDataChannel",channelProp,"initializing main DataChannel"])),dataChannel.onerror=function(evt){var channelError=evt.error||evt;log.error([peerId,"RTCDataChannel",channelProp,"Datachannel has an exception ->"],channelError),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,channelError,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onbufferedamountlow=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel buffering data transfer low"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.BUFFERED_AMOUNT_LOW,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onmessage=function(event){self._processDataChannelData(event.data,peerId,channelName,channelType)};var onOpenHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has opened"]),dataChannel.bufferedAmountLowThreshold=bufferThreshold||0,self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.OPEN,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))};dataChannel.readyState===self.DATA_CHANNEL_STATE.OPEN?setTimeout(onOpenHandlerFn,1):(self._trigger("dataChannelState",dataChannel.readyState,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),dataChannel.onopen=onOpenHandlerFn);var onCloseHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has closed"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSED,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),self._peerConnections[peerId]&&self._peerConnections[peerId].remoteDescription&&self._peerConnections[peerId].remoteDescription.sdp&&(-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"===window.webrtcDetectedBrowser){var hasTriggeredClose=!1,timeBlockAfterClosing=0;dataChannel.onclose=function(){hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())};var onFFClosed=setInterval(function(){dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSED||hasTriggeredClose||5===timeBlockAfterClosing?(clearInterval(onFFClosed),hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())):dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSING&&timeBlockAfterClosing++},1e3)}else dataChannel.onclose=onCloseHandlerFn;channelType===self.DATA_CHANNEL_TYPE.MESSAGING?self._dataChannels[peerId].main={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}:self._dataChannels[peerId][channelName]={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}},Skylink.prototype._getDataChannelBuffer=function(peerId,channelProp){if("object"==typeof peerId)return{bufferedAmountLow:"number"==typeof peerId.bufferedAmountLow?peerId.bufferedAmountLow:parseInt(peerId.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof peerId.bufferedAmountLowThreshold?peerId.bufferedAmountLowThreshold:parseInt(peerId.bufferedAmountLowThreshold,10)||0};if(!(this._dataChannels[peerId]&&this._dataChannels[peerId][channelProp]&&this._dataChannels[peerId][channelProp].channel))return{bufferedAmountLow:0,bufferedAmountLowThreshold:0};var channel=this._dataChannels[peerId][channelProp].channel;return{bufferedAmountLow:"number"==typeof channel.bufferedAmountLow?channel.bufferedAmountLow:parseInt(channel.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof channel.bufferedAmountLowThreshold?channel.bufferedAmountLowThreshold:parseInt(channel.bufferedAmountLowThreshold,10)||0}},Skylink.prototype._sendMessageToDataChannel=function(peerId,data,channelProp,doNotConvert){var self=this;if(channelProp&&channelProp!==peerId||(channelProp="main"),!("object"==typeof data&&data||data&&"string"==typeof data))return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping invalid data ->"],data);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Peer connection does not exists or is closed ->"],data);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Datachannel connection does not exists ->"],data);var channelName=self._dataChannels[peerId][channelProp].channelName,channelType=self._dataChannels[peerId][channelProp].channelType,readyState=self._dataChannels[peerId][channelProp].channel.readyState,messageType="object"==typeof data&&data.type===self._DC_PROTOCOL_TYPE.MESSAGE?self.DATA_CHANNEL_MESSAGE_ERROR.MESSAGE:self.DATA_CHANNEL_MESSAGE_ERROR.TRANSFER;if(readyState!==self.DATA_CHANNEL_STATE.OPEN){var notOpenError='Failed sending message as Datachannel connection state is not opened. Current readyState is "'+readyState+'"';throw log.error([peerId,"RTCDataChannel",channelProp,notOpenError+" ->"],data),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,new Error(notOpenError),channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),new Error(notOpenError)}try{doNotConvert||"object"!=typeof data?(log.debug([peerId,"RTCDataChannel",channelProp,"Sending data with size ->"],data.size||data.length||data.byteLength),self._dataChannels[peerId][channelProp].channel.send(data)):(log.debug([peerId,"RTCDataChannel",channelProp,'Sending "'+data.type+'" protocol message ->'],data),self._dataChannels[peerId][channelProp].channel.send(JSON.stringify(data)))}catch(error){throw log.error([peerId,"RTCDataChannel",channelProp,"Failed sending "+(doNotConvert||"object"!=typeof data?"data":'"'+data.type+'" protocol message')+" ->"],error),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,error,channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),error}},Skylink.prototype._closeDataChannel=function(peerId,channelProp){var self=this;if(!self._dataChannels[peerId])return void log.warn([peerId,"RTCDataChannel",channelProp||null,"Aborting closing Datachannels as Peer connection does not have Datachannel sessions"]);var closeFn=function(rChannelProp){var channelName=self._dataChannels[peerId][rChannelProp].channelName,channelType=self._dataChannels[peerId][rChannelProp].channelType;self._dataChannels[peerId][rChannelProp].readyState!==self.DATA_CHANNEL_STATE.CLOSED&&(log.debug([peerId,"RTCDataChannel",channelProp,"Closing Datachannel"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSING,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(peerId,rChannelProp)),self._dataChannels[peerId][rChannelProp].channel.close(),delete self._dataChannels[peerId][rChannelProp])};if(channelProp){if(!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Aborting closing Datachannel as it does not exists"]);closeFn(channelProp)}else for(var channelNameProp in self._dataChannels)self._dataChannels[peerId].hasOwnProperty(channelNameProp)&&self._dataChannels[peerId][channelNameProp]&&closeFn(channelNameProp)},Skylink.prototype.DATA_TRANSFER_DATA_TYPE={BINARY_STRING:"binaryString",ARRAY_BUFFER:"arrayBuffer",BLOB:"blob",STRING:"string"},Skylink.prototype._CHUNK_FILE_SIZE=49152,Skylink.prototype._MOZ_CHUNK_FILE_SIZE=12288,Skylink.prototype._BINARY_FILE_SIZE=65456,Skylink.prototype._MOZ_BINARY_FILE_SIZE=16384,Skylink.prototype._CHUNK_DATAURL_SIZE=1212,Skylink.prototype._base64ToBlob=function(dataURL){for(var byteString=atob(dataURL),ab=new ArrayBuffer(byteString.length),ia=new Uint8Array(ab),j=0;jchunkSize){for(;blobByteSize-1>endCount;)endCount=startCount+chunkSize,chunksArray.push(blob.slice(startCount,endCount)),startCount+=chunkSize;blobByteSize-(startCount+1)>0&&chunksArray.push(blob.slice(startCount,blobByteSize-1))}else chunksArray.push(blob);return chunksArray},Skylink.prototype._chunkDataURL=function(dataURL,chunkSize){var outputStr=dataURL,dataURLArray=[],startCount=0,endCount=0,dataByteSize=dataURL.size||dataURL.length;if(dataByteSize>chunkSize){for(;dataByteSize-1>endCount;)endCount=startCount+chunkSize,dataURLArray.push(outputStr.slice(startCount,endCount)),startCount+=chunkSize;dataByteSize-(startCount+1)>0&&chunksArray.push(outputStr.slice(startCount,dataByteSize-1))}else dataURLArray.push(outputStr);return dataURLArray},Skylink.prototype.DT_PROTOCOL_VERSION="0.1.3",Skylink.prototype.DATA_TRANSFER_TYPE={UPLOAD:"upload",DOWNLOAD:"download"},Skylink.prototype.DATA_TRANSFER_SESSION_TYPE={BLOB:"blob",DATA_URL:"dataURL"},Skylink.prototype.DATA_TRANSFER_STATE={UPLOAD_REQUEST:"request",UPLOAD_STARTED:"uploadStarted",DOWNLOAD_STARTED:"downloadStarted",REJECTED:"rejected",CANCEL:"cancel",ERROR:"error",UPLOADING:"uploading",DOWNLOADING:"downloading",UPLOAD_COMPLETED:"uploadCompleted",DOWNLOAD_COMPLETED:"downloadCompleted",USER_REJECTED:"userRejected",USER_UPLOAD_REQUEST:"userRequest",START_ERROR:"startError"},Skylink.prototype.DATA_STREAM_STATE={SENDING_STARTED:"sendStart",SENDING_STOPPED:"sendStop",RECEIVING_STARTED:"receiveStart",RECEIVING_STOPPED:"receiveStop",RECEIVED:"received",SENT:"sent",ERROR:"error",START_ERROR:"startError"},Skylink.prototype._DC_PROTOCOL_TYPE={WRQ:"WRQ",ACK:"ACK",ERROR:"ERROR",CANCEL:"CANCEL",MESSAGE:"MESSAGE"},Skylink.prototype.sendBlobData=function(data,timeout,targetPeerId,sendChunksAsBinary,callback){this._startDataTransfer(data,timeout,targetPeerId,sendChunksAsBinary,callback,"blob")},Skylink.prototype.sendURLData=function(data,timeout,targetPeerId,callback){this._startDataTransfer(data,timeout,targetPeerId,callback,null,"data")},Skylink.prototype.respondBlobRequest=Skylink.prototype.acceptDataTransfer=function(peerId,transferId,accept){var self=this;if("string"!=typeof transferId&&"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as data transfer ID or peer ID is not provided"]);if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as Peer does not have any Datachannel connections"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as invalid transfer ID is provided"]);var channelProp="main";if(self._dataChannels[peerId][transferId]&&(channelProp=transferId),accept){log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]);var dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){console.info(evtPeerId,error,cN,cT),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD,message:new Error("Data transfer terminated as Peer Datachannel connection closed abruptly.")})};self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_STATE.MESSAGING:channelName===transferId)&&[self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED,self.DATA_CHANNEL_STATE.ERROR].indexOf(state)>-1:void self.off("dataChannelState",dataChannelStateCbFn)}),self.once("dataTransferState",function(){dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),delete self._dataTransfers[transferId],self._dataChannels[peerId]&&("main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),channelProp===transferId&&self._closeDataChannel(peerId,transferId))},function(state,evtTransferId,evtPeerId){return evtTransferId===transferId&&evtPeerId===peerId&&[self.DATA_TRANSFER_STATE.ERROR,self.DATA_TRANSFER_STATE.CANCEL,self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED].indexOf(state)>-1}),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:0},channelProp),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_STARTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)}else log.warn([peerId,"RTCDataChannel",transferId,"Rejected data transfer and data transfer request has been aborted"]),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:-1},channelProp),"main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.USER_REJECTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as User has rejected data transfer request."),transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD}),delete self._dataTransfers[transferId]},Skylink.prototype.cancelBlobTransfer=Skylink.prototype.cancelDataTransfer=function(peerId,transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer ID is not provided"]);if(!peerId||"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as peer ID is not provided"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer session does not exists."]);log.debug([peerId,"RTCDataChannel",transferId,"Canceling data transfer ..."]);var emitEventFn=function(peers,transferInfoPeerId){for(var i=0;i0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},"main"),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},transferId),emitEventFn(Object.keys(self._dataTransfers[transferId].peers.main).concat(Object.keys(self._dataTransfers[transferId].peers[transferId])))}else{var channelProp="main";if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as Peer does not have any Datachannel connections"]);self._dataChannels[peerId][transferId]&&(channelProp=transferId),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},channelProp),emitEventFn([peerId],peerId)}},Skylink.prototype.sendP2PMessage=function(message,targetPeerId){var listOfPeers=Object.keys(this._dataChannels),isPrivate=!1;if(Array.isArray(targetPeerId)?(listOfPeers=targetPeerId,isPrivate=!0):targetPeerId&&"string"==typeof targetPeerId&&(listOfPeers=[targetPeerId],isPrivate=!0),!this._inRoom||!this._user||!this._user.sid)return void log.error("Unable to send message as User is not in Room. ->",message);if(!this._enableDataChannel)return void log.error("Unable to send message as User does not have Datachannel enabled. ->",message);for(var i=0;i-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeStreamingFn=function(error){log.error(error)};if(!this._inRoom||!this._user||!this._user.sid)return emitErrorBeforeStreamingFn("Unable to start data streaming as User is not in Room.");if(!this._enableDataChannel)return emitErrorBeforeStreamingFn("Unable to start data streaming as User does not have Datachannel enabled.");if(0===listOfPeers.length)return emitErrorBeforeStreamingFn("Unable to start data streaming as there are no Peers to start session with.");if(self._hasMCU)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature is current not supported by MCU yet.");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},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"===window.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE)};if(peersNonInterop.length>0)if(self._hasMCU)waitForChannelOpenFn("MCU",peersNonInterop);else for(var pni=0;pni0)if(self._hasMCU)startDataSessionFn("MCU","main",peersInterop);else for(var pi=0;piself._CHUNK_DATAURL_SIZE:updatedDataChunk.length>self._BINARY_FILE_SIZE)return void log.error("Failed streaming data chunk as data chunk exceeds maximum chunk limit.");var sessionInfo={chunk:updatedDataChunk,chunkSize:updatedDataChunk.size||updatedDataChunk.length||updatedDataChunk.byteLength,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){var onSendDataFn=function(buffer){self._sendMessageToDataChannel(peerId,buffer,channelProp,!0);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i-1&&"string"!=typeof dataChunk?new Int8Array(dataChunk):dataChunk:new Blob([dataChunk]))};for(var peerId in self._dataStreams[transferId].sessions)if(self._dataStreams[transferId].sessions.hasOwnProperty(peerId)&&self._dataStreams[transferId].sessions[peerId]){var channelProp=self._dataStreams[transferId].sessions[peerId];if(!self._dataChannels[self._hasMCU?"MCU":peerId]||!self._dataChannels[self._hasMCU?"MCU":peerId][channelProp]||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].channel.readyState!==self.DATA_CHANNEL_STATE.OPEN||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].streamId!==transferId)return log.error([peerId,"RTCDataChannel",transferId,"Failed streaming data as it has not started or is ready."]),void self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,peerId,sessionInfo,new Error("Streaming as it has not started or Datachannel connection is not open."));self._hasMCU?"main"===channelProp?peersInterop.push(peerId):peersNonInterop.push(peerId):sendDataFn(peerId,channelProp)}self._hasMCU&&(peersInterop.length>0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype.stopStreamingData=function(transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error("Failed streaming data chunk as stream session ID is not provided.");if(!(self._inRoom&&self._user&&self._user.sid))return void log.error("Failed streaming data chunk as User is not in the Room.");if(!self._dataStreams[transferId])return void log.error("Failed stopping data streaming session as it does not exists.");if(!self._dataStreams[transferId].isUpload)return void log.error("Failed stopping data streaming session as it is not sending.");if(self._hasMCU)return void log.error("Failed stopping data streaming session as MCU does not support this feature yet.");var sessionInfo={chunk:null,chunkSize:0,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:transferId,size:0,originalSize:0,dataType:"fastBinaryStop",mimeType:null,chunkType:self._dataStreams[transferId].sessionChunkType,chunkSize:0,timeout:0,isPrivate:self._dataStreams[transferId].isPrivate,sender:self._user.sid,agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers||peerId},channelProp);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype._startDataTransfer=function(data,timeout,targetPeerId,sendChunksAsBinary,callback,sessionType){var self=this,transferId=(self._user?self._user.sid:"")+"_"+(new Date).getTime(),transferErrors={},transferCompleted=[],chunks=[],listOfPeers=Object.keys(self._peerConnections),sessionChunkType="string",transferInfo={name:null,size:null,chunkSize:null,chunkType:null,dataType:null,mimeType:null,direction:self.DATA_TRANSFER_TYPE.UPLOAD,timeout:60,isPrivate:!1,percentage:0};"number"==typeof timeout?transferInfo.timeout=timeout:Array.isArray(timeout)?listOfPeers=timeout:timeout&&"string"==typeof timeout?listOfPeers=[timeout]:timeout&&"boolean"==typeof timeout?sessionChunkType="binary":"function"==typeof timeout&&(callback=timeout),Array.isArray(targetPeerId)?listOfPeers=targetPeerId:targetPeerId&&"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:targetPeerId&&"boolean"==typeof targetPeerId?sessionChunkType="binary":"function"==typeof targetPeerId&&(callback=targetPeerId),sendChunksAsBinary&&"boolean"==typeof sendChunksAsBinary?sessionChunkType="binary":"function"==typeof sendChunksAsBinary&&(callback=sendChunksAsBinary),listOfPeers.indexOf("MCU")>-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeDataTransferFn=function(error){if(log.error(error),"function"==typeof callback){var transferErrors={};if(0===listOfPeers.length)transferErrors.self=new Error(error);else for(var i=0;i0){var bsChunkSize="firefox"===window.webrtcDetectedBrowser?self._MOZ_CHUNK_FILE_SIZE:self._CHUNK_FILE_SIZE,bsChunks=self._chunkBlobData(new Blob(chunks),bsChunkSize);self._dataTransfers[transferId].enforceBSInfo={chunkSize:4*Math.ceil(bsChunkSize/3),chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,size:4*Math.ceil(transferInfo.originalSize/3),chunks:bsChunks}}}for(var completeFn=function(peerId,error){transferCompleted.indexOf(peerId)>-1||(log.debug([peerId,"RTCDataChannel",transferId,"Data transfer result. Is errors present? ->"],error),transferCompleted.push(peerId),error&&(transferErrors[peerId]=new Error(error)),listOfPeers.length===transferCompleted.length&&(log.log([null,"RTCDataChannel",transferId,"Data transfer request completed"]),"function"==typeof callback&&(Object.keys(transferErrors).length>0?callback({transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),transferErrors:transferErrors,listOfPeers:listOfPeers},null):callback(null,{transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),listOfPeers:listOfPeers}))))},i=0;i0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,"main",Object.keys(self._dataTransfers[transferId].peers.main)),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,transferId,Object.keys(self._dataTransfers[transferId].peers[transferId])))},Skylink.prototype._startDataTransferToPeer=function(transferId,peerId,callback,channelProp,targetPeers){var self=this,peerConnectionStateCbFn=null,dataChannelStateCbFn=null,emitEventFn=function(cb){for(var peers=targetPeers||[peerId],i=0;i-1&&(log.warn([peerId,"RTCDataChannel",transferId,"Binary data chunks transfer is not yet supported with Peer connecting from Android, iOS and C++ SDK. Fallbacking to binary string data chunks transfer."]),size=self._dataTransfers[transferId].enforceBSInfo.size,chunkSize=self._dataTransfers[transferId].enforceBSInfo.chunkSize,chunkType="string"),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:self._dataTransfers[transferId].name,size:size,originalSize:self._dataTransfers[transferId].originalSize,dataType:self._dataTransfers[transferId].sessionType,mimeType:self._dataTransfers[transferId].mimeType,chunkType:chunkType,chunkSize:chunkSize,timeout:self._dataTransfers[transferId].timeout,isPrivate:self._dataTransfers[transferId].isPrivate,sender:self._user.sid,agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers||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");return self._isLowerThanVersion(protocolVer,"0.1.2")&&"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer do not support DATA_URL type of data transfers"):"MCU"!==peerId&&self._hasMCU?(channelProp=requireInterop?"main":transferId,peerConnectionStateCbFn=function(){returnErrorBeforeTransferFn("Data transfer terminated as Peer connection is not stable.")},self.once("peerConnectionState",peerConnectionStateCbFn,function(state,evtPeerId){return self._dataTransfers[transferId]?state!==self.PEER_CONNECTION_STATE.STABLE&&evtPeerId===peerId:void self.off("peerConnectionState",peerConnectionStateCbFn)}),requireInterop):(requireInterop||"main"===channelProp)&&self._dataChannels[peerId].main.transferId?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel has a data transfer in-progress."):(self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0},dataChannelStateCbFn=function(state,evtPeerId,error){self._dataTransfers[transferId].sessions[peerId].ackN>=self._dataTransfers[transferId].chunks.length-1||returnErrorBeforeTransferFn(error?error.message||error.toString():"Data transfer terminated as Peer Datachannel connection closed abruptly.")},self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName===transferId?(self._dataChannels[peerId][channelProp].transferId=transferId,sendWRQFn(),!1):[self.DATA_CHANNEL_STATE.CREATE_ERROR,self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1:void self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(self._dataChannels[peerId].main.transferId=transferId,sendWRQFn()):(channelProp=transferId,self._createDataChannel(peerId,transferId,"data"===self._dataTransfers[transferId].sessionType?self._CHUNK_DATAURL_SIZE:"string"===self._dataTransfers[transferId].sessionChunkType?"firefox"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE))))},Skylink.prototype._getTransferInfo=function(transferId,peerId,returnDataProp,hidePercentage,returnDataAtStart){if(!this._dataTransfers[transferId])return{};var transferInfo={name:this._dataTransfers[transferId].name,size:this._dataTransfers[transferId].size,dataType:this._dataTransfers[transferId].dataType||this.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:this._dataTransfers[transferId].mimeType||null,chunkSize:this._dataTransfers[transferId].chunkSize,chunkType:this._dataTransfers[transferId].chunkType,timeout:this._dataTransfers[transferId].timeout,isPrivate:this._dataTransfers[transferId].isPrivate,direction:this._dataTransfers[transferId].direction};if(this._dataTransfers[transferId].originalSize?transferInfo.size=this._dataTransfers[transferId].originalSize:this._dataTransfers[transferId].chunkType===this.DATA_TRANSFER_DATA_TYPE.BINARY_STRING&&(transferInfo.size=Math.ceil(3*transferInfo.size/4)),!hidePercentage){if(transferInfo.percentage=0,!this._dataTransfers[transferId].sessions[peerId])return returnDataProp&&(transferInfo.data=null),transferInfo;if(this._dataTransfers[transferId].direction===this.DATA_TRANSFER_TYPE.DOWNLOAD)this._dataTransfers[transferId].sessions[peerId].receivedSize===this._dataTransfers[transferId].sessions[peerId].size?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].receivedSize/this._dataTransfers[transferId].size*100).toFixed(2),10);else{var chunksLength=this._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?this._dataTransfers[transferId].enforceBSInfo.chunks.length:this._dataTransfers[transferId].chunks.length;this._dataTransfers[transferId].sessions[peerId].ackN===chunksLength?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].ackN/chunksLength*100).toFixed(2),10)}returnDataProp&&("number"!=typeof returnDataAtStart?100===transferInfo.percentage?transferInfo.data=this._getTransferData(transferId):transferInfo.data=null:(transferInfo.percentage=returnDataAtStart,0===returnDataAtStart&&(transferInfo.data=this._getTransferData(transferId))))}return transferInfo},Skylink.prototype._getTransferData=function(transferId){if(!this._dataTransfers[transferId])return null;if(this._dataTransfers[transferId].dataType===this.DATA_TRANSFER_SESSION_TYPE.BLOB){var mimeType={name:this._dataTransfers[transferId].name};return this._dataTransfers[transferId].mimeType&&(mimeType.type=this._dataTransfers[transferId].mimeType),new Blob(this._dataTransfers[transferId].chunks,mimeType)}return this._dataTransfers[transferId].chunks.join("")},Skylink.prototype._handleDataTransferTimeoutForPeer=function(transferId,peerId,setPeerTO){var self=this;if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer does not exists for Peer. Ignoring timeout."]);log.debug([peerId,"RTCDataChannel",transferId,"Clearing data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer&&clearTimeout(self._dataTransfers[transferId].sessions[peerId].timer),self._dataTransfers[transferId].sessions[peerId].timer=null,setPeerTO&&(log.debug([peerId,"RTCDataChannel",transferId,"Setting data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer=setTimeout(function(){if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer already ended for Peer. Ignoring expired timeout."]);if(!self._user||!self._user.sid)return void log.debug([peerId,"RTCDataChannel",transferId,"User is not in Room. Ignoring expired timeout."]);if(!self._dataChannels[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Datachannel connection does not exists. Ignoring expired timeout."]);log.error([peerId,"RTCDataChannel",transferId,"Data transfer response has timed out."]);var 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"===window.webrtcDetectedBrowser){if(window.BlobBuilder){var bb=new BlobBuilder;bb.append(rawData.constructor&&"ArrayBuffer"===rawData.constructor.name?byteArray:new Uint8Array(byteArray).buffer),blob=bb.getBlob()}}else blob=new Blob([byteArray]);log.debug([peerId,"RTCDataChannel",channelProp,"Received arraybuffer data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],blob.size),self._DATAProtocolHandler(peerId,blob,self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,blob.size,channelProp)}}},Skylink.prototype._WRQProtocolHandler=function(peerId,data,channelProp){var self=this,transferId="main"===channelProp?data.transferId||null:channelProp,senderPeerId=data.sender||peerId;if(["fastBinaryStart","fastBinaryStop"].indexOf(data.dataType)>-1)if("fastBinaryStart"===data.dataType){transferId||(transferId="stream_"+peerId+"_"+(new Date).getTime()),self._dataStreams[transferId]={chunkSize:0,chunkType:"string"===data.chunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:data.chunkType,isPrivate:!!data.isPrivate,isStringStream:"string"===data.chunkType,senderPeerId:senderPeerId,isUpload:!1},self._dataChannels[peerId][channelProp].streamId=transferId;self.once("dataChannelState",function(){},function(state,evtPeerId,channelName,channelType,error){if(!self._dataStreams[transferId])return!0;if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId&&channelType===self.DATA_CHANNEL_TYPE.DATA)&&[self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');return self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},updatedError),!0}}),self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STARTED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStarted",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1)}else transferId=self._dataChannels[peerId][channelProp].streamId,self._dataStreams[transferId]&&!self._dataStreams[transferId].isUpload&&(self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STOPPED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStopped",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1),self._dataChannels[peerId][channelProp].streamId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp),delete self._dataStreams[transferId]);else transferId||(transferId="transfer_"+peerId+"_"+(new Date).getTime()),self._dataTransfers[transferId]={name:data.name||transferId,size:data.size||0,chunkSize:data.chunkSize,originalSize:data.originalSize||0,timeout:data.timeout||60,isPrivate:!!data.isPrivate,senderPeerId:data.sender||peerId,dataType:self.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:data.mimeType||null,chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,direction:self.DATA_TRANSFER_TYPE.DOWNLOAD,chunks:[],sessions:{},sessionType:data.dataType||"blob",sessionChunkType:data.chunkType||"string"},"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?(self._dataTransfers[transferId].dataType=self.DATA_TRANSFER_SESSION_TYPE.DATA_URL,self._dataTransfers[transferId].chunkType=self.DATA_TRANSFER_DATA_TYPE.STRING):"blob"===self._dataTransfers[transferId].sessionType&&"binary"===self._dataTransfers[transferId].sessionChunkType&&(self._dataTransfers[transferId].chunkType=self._binaryChunkType),self._dataChannels[peerId][channelProp].transferId=transferId,self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0,receivedSize:0},self._trigger("incomingDataRequest",transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!1),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_REQUEST,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)},Skylink.prototype._ACKProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ACK event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};if(data.ackN>-1){if(0===data.ackN)emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_STARTED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,0),null)});else if(self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?data.ackN===self._dataTransfers[transferId].enforceBSInfo.chunks.length:data.ackN===self._dataTransfers[transferId].chunks.length)return self._dataTransfers[transferId].sessions[peerId].ackN=data.ackN,emitEventFn(function(evtPeerId){self._trigger("incomingData",self._getTransferData(transferId),transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,100),null)}),void(self._dataChannels[peerId][channelProp]&&(self._dataChannels[peerId][channelProp].transferId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp)));var uploadFn=function(chunk){self._sendMessageToDataChannel(peerId,chunk,channelProp,!0),data.ackN-1?self._blobToBase64(self._dataTransfers[transferId].enforceBSInfo.chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING?self._blobToBase64(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER?self._blobToArrayBuffer(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):uploadFn(self._dataTransfers[transferId].chunks[data.ackN])}else self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.REJECTED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as Peer has rejected data transfer request"),transferType:self.DATA_TRANSFER_TYPE.UPLOAD})},Skylink.prototype._MESSAGEProtocolHandler=function(peerId,data,channelProp){var senderPeerId=data.sender||peerId;log.log([senderPeerId,"RTCDataChannel",channelProp,"Received P2P message from peer:"],data),this._trigger("incomingMessage",{content:data.data,isPrivate:data.isPrivate,isDataChannel:!0,targetPeerId:this._user.sid,senderPeerId:senderPeerId},senderPeerId,this.getPeerInfo(senderPeerId),!1)},Skylink.prototype._ERRORProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,userInfo:self._getUserInfo(targetMid),target:targetMid,rid:self._room.id})}}},Skylink.prototype._addIceCandidateToQueue=function(targetMid,canId,candidate){var candidateType=candidate.candidate.split(" ")[7];log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Buffering ICE candidate."]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.BUFFERED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[],this._peerCandidatesQueue[targetMid].push([canId,candidate])},Skylink.prototype._addIceCandidateFromQueue=function(targetMid){this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[];for(var i=0;i"],error),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESS_ERROR,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},error)};if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Adding ICE candidate."]),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESSING,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[targetMid].remoteDescription&&self._peerConnections[targetMid].remoteDescription.sdp&&self._peerConnections[targetMid].remoteDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),void self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),-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"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}},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"===window.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;if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]),"edge"===window.webrtcDetectedBrowser)return callback(new Error("Edge does not support stats"));if(!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},Skylink.prototype._addPeer=function(targetMid,cert,peerBrowser,receiveOnly,isSS){var self=this;return self._peerConnections[targetMid]?void log.error([targetMid,null,null,"Connection to peer has already been made"]):(self._peerConnStatus[targetMid]={connected:!1,init:!1},log.log([targetMid,null,null,"Starting the connection to peer. Options provided:"],{peerBrowser:peerBrowser,receiveOnly:receiveOnly,enableDataChannel:self._enableDataChannel}),log.info("Adding peer",isSS),self._peerConnections[targetMid]=self._createPeerConnection(targetMid,!!isSS,cert),self._peerConnections[targetMid]?(self._peerConnStatus[targetMid].init=!0,void(self._peerConnections[targetMid].hasScreen=!!isSS)):void log.error([targetMid,null,null,"Failed creating the connection to peer."]))},Skylink.prototype._restartPeerConnection=function(peerId,doIceRestart,bwOptions,callback){var self=this;if(!self._peerConnections[peerId])return void log.error([peerId,null,null,"Peer does not have an existing connection. Unable to restart"]);var pc=self._peerConnections[peerId],agent=(self.getPeerInfo(peerId)||{}).agent||{};if(self._isLowerThanVersion(agent.SMProtocolVersion||"","0.1.2")){var notSupportedError=new Error("Failed restarting with other agents connecting from other SDKs as re-negotiation is not supported by other SDKs");return log.warn([peerId,"RTCPeerConnection",null,"Ignoring restart request as agent's SDK does not support it"],notSupportedError),void("function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(notSupportedError)))}if(pc.signalingState===self.PEER_CONNECTION_STATE.STABLE&&self._peerConnections[peerId]){log.log([peerId,null,null,"Sending restart message to signaling server ->"],{iceRestart:doIceRestart,options:bwOptions}),self._peerCustomConfigs[peerId]=self._peerCustomConfigs[peerId]||{},self._peerCustomConfigs[peerId].bandwidth=self._peerCustomConfigs[peerId].bandwidth||{},self._peerCustomConfigs[peerId].googleXBandwidth=self._peerCustomConfigs[peerId].googleXBandwidth||{},bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._peerCustomConfigs[peerId].bandwidth.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._peerCustomConfigs[peerId].bandwidth.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._peerCustomConfigs[peerId].bandwidth.data=bwOptions.bandwidth.data)), +bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._peerCustomConfigs[peerId].googleXBandwidth.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._peerCustomConfigs[peerId].googleXBandwidth.max=bwOptions.googleXBandwidth.max));var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!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(),"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,self._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}},self._streamsSession[targetMid]=self._streamsSession[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._sdpSessions[targetMid]={local:{},remote:{}},self._peerBandwidth[targetMid]={};var bandwidth=null;return pc.ondatachannel=function(event){var dc=event.channel||event;if(log.debug([targetMid,"RTCDataChannel",dc.label,"Received datachannel ->"],dc),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel){self.DATA_CHANNEL_TYPE.DATA,dc.label;pc.hasMainChannel||(self.DATA_CHANNEL_TYPE.MESSAGING,"main",pc.hasMainChannel=!0),self._createDataChannel(targetMid,dc)}else log.warn([targetMid,"RTCDataChannel",dc.label,"Not adding datachannel as enable datachannel is set to false"])},pc.onaddstream=function(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&-1===pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" "))return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},pc.onicecandidate=function(event){self._onIceCandidate(targetMid,event.candidate||event)},pc.oniceconnectionstatechange=function(evt){var iceConnectionState=pc.iceConnectionState;if(log.debug([targetMid,"RTCIceConnectionState",null,"Ice connection state changed ->"],iceConnectionState),"edge"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._enableIceTrickle&&self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.TRICKLE_FAILED,targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].connected=[self.ICE_CONNECTION_STATE.COMPLETED,self.ICE_CONNECTION_STATE.CONNECTED].indexOf(iceConnectionState)>-1),!self._hasMCU&&[self.ICE_CONNECTION_STATE.CONNECTED,self.ICE_CONNECTION_STATE.COMPLETED].indexOf(iceConnectionState)>-1&&self._bandwidthAdjuster&&!bandwidth&&"edge"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),self._trigger("peerConnectionState",pc.signalingState,targetMid)},pc.onicegatheringstatechange=function(){log.log([targetMid,"RTCIceGatheringState",null,"Ice gathering state changed ->"],pc.iceGatheringState),self._trigger("candidateGenerationState",pc.iceGatheringState,targetMid)},"firefox"===window.webrtcDetectedBrowser&&(pc.removeStream=function(stream){for(var senders=pc.getSenders(),s=0;s"],restartMsg),self._sendChannelMessage(restartMsg)};bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=bwOptions.googleXBandwidth.max));for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers},null):callback(null,{listOfPeers:listOfPeers}))};self.once("peerJoined",peerJoinedFn,function(peerId,peerInfo,isSelf){return isSelf}),self.leaveRoom(!1,function(error,success){if(error){if("function"==typeof callback){for(var i=0;i=self._peerEndOfCandidatesCounter[targetMid].expectedLen&&(!self._peerCandidatesQueue[targetMid]||0===self._peerCandidatesQueue[targetMid].length)&&!self._peerEndOfCandidatesCounter[targetMid].hasSet){log.debug([targetMid,"RTCPeerConnection",null,"Signaling of end-of-candidates remote ICE gathering."]),self._peerEndOfCandidatesCounter[targetMid].hasSet=!0;try{if("edge"===window.webrtcDetectedBrowser){for(var mLineCounter=-1,addedMids=[],sdpLines=self._peerConnections[targetMid].remoteDescription.sdp.split("\r\n"),rejected=!1,i=0;i"],error)}}},Skylink.prototype.setUserData=function(userData){var self=this,updatedUserData="";void 0!==userData&&null!==userData&&(updatedUserData=userData),this._userData=updatedUserData,self._inRoom?(log.log("Updated userData -> ",updatedUserData),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.UPDATE_USER,mid:self._user.sid,rid:self._room.id,userData:updatedUserData,stamp:(new Date).getTime()}),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0)):log.warn("User is not in the room. Broadcast of updated information will be dropped")},Skylink.prototype.getUserData=function(peerId){if(peerId&&this._peerInformations[peerId]){var userData=this._peerInformations[peerId].userData;return null!==userData&&void 0===userData||(userData=""),userData}return this._userData},Skylink.prototype.getPeerInfo=function(peerId){var peerInfo=null;return"string"==typeof peerId&&"object"==typeof this._peerInformations[peerId]?(peerInfo=clone(this._peerInformations[peerId]),peerInfo.room=clone(this._selectedRoom),peerInfo.settings.bandwidth=peerInfo.settings.bandwidth||{},peerInfo.settings.googleXBandwidth=peerInfo.settings.googleXBandwidth||{},"boolean"==typeof peerInfo.settings.video||peerInfo.settings.video&&"object"==typeof peerInfo.settings.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"==typeof peerInfo.settings.audio||peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.audioMuted&&(peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.videoMuted&&(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.maxBandwidth&&(peerInfo.settings.bandwidth=clone(peerInfo.settings.maxBandwidth),delete peerInfo.settings.maxBandwidth),peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&peerInfo.settings.video.customSettings&&"object"==typeof peerInfo.settings.video.customSettings&&(peerInfo.settings.video.customSettings.frameRate&&(peerInfo.settings.video.frameRate=clone(peerInfo.settings.video.customSettings.frameRate)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode)),peerInfo.settings.video.customSettings.width&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.width=clone(peerInfo.settings.video.customSettings.width)),peerInfo.settings.video.customSettings.height&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.height=clone(peerInfo.settings.video.customSettings.height)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode))),peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&(peerInfo.settings.audio.stereo=!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)),this._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0)):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,os:window.navigator.platform,pluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:this.SMProtocolVersion,DTProtocolVersion:this.DTProtocolVersion},room:clone(this._selectedRoom),config:{enableDataChannel:this._enableDataChannel,enableIceTrickle:this._enableIceTrickle,enableIceRestart:this._enableIceRestart,priorityWeight:this._peerPriorityWeight,receiveOnly:!1,publishOnly:!!this._publishOnly},connected:null,init:null},null!==peerInfo.userData&&void 0!==peerInfo.userData||(peerInfo.userData=""),this._streams.screenshare?peerInfo.settings=clone(this._streams.screenshare.settings):this._streams.userMedia&&(peerInfo.settings=clone(this._streams.userMedia.settings)),peerInfo.settings.bandwidth=clone(this._streamsBandwidthSettings.bAS),peerInfo.settings.googleXBandwidth=clone(this._streamsBandwidthSettings.googleX),peerInfo.parentId=this._parentId?this._parentId:null,peerInfo.config.receiveOnly=!peerInfo.settings.video&&!peerInfo.settings.audio,peerInfo.settings.data=this._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._codecParams.audio.opus.useinbandfec))),peerInfo.settings.audio||(peerInfo.mediaStatus.audioMuted=!0),peerInfo.settings.video||(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.audio||peerInfo.settings.video||(peerInfo.config.receiveOnly=!0,peerInfo.config.publishOnly=!1),peerInfo},Skylink.prototype.getPeersInRoom=function(){for(var listOfPeersInfo={},listOfPeers=Object.keys(this._peerInformations),i=0;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i-1||(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.settings.video&&!self._getSDPEdgeVideoSupports(usePeerId)&&(customSettings.settings.video=!1,customSettings.mediaStatus.videoMuted=!0),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),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype.HANDSHAKE_PROGRESS={ENTER:"enter",WELCOME:"welcome",OFFER:"offer",ANSWER:"answer",ERROR:"error"},Skylink.prototype._doOffer=function(targetMid,iceRestart,peerBrowser){var self=this,pc=self._peerConnections[targetMid];if(log.log([targetMid,null,null,"Checking caller status"],peerBrowser),!pc)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of creating of offer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription","offer",'Dropping of creating of offer as signalingState is not "'+self.PEER_CONNECTION_STATE.STABLE+'" ->'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._dataChannels[targetMid]&&self._dataChannels[targetMid].main||(self._createDataChannel(targetMid),self._peerConnections[targetMid].hasMainChannel=!0)),log.debug([targetMid,null,null,"Creating offer with config:"],offerConstraints),pc.endOfCandidates=!1,self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=offerConstraints),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},offerConstraints)},Skylink.prototype._doAnswer=function(targetMid){var self=this;log.log([targetMid,null,null,"Creating answer with config:"],self._room.connection.sdpConstraints);var pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of creating of answer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription","answer",'Dropping of creating of answer as signalingState is not "'+self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER+'" ->'],pc.signalingState);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,_sessionDescription){var self=this,pc=self._peerConnections[targetMid];if(!_sessionDescription||!_sessionDescription.sdp)return void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],_sessionDescription);if(!pc)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as connection does not exists ->"],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(pc.processingLocalSDP)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as another is being processed ->"],_sessionDescription);pc.processingLocalSDP=!0;var sessionDescription={type:_sessionDescription.type,sdp:_sessionDescription.sdp};sessionDescription.sdp=self._removeSDPFirefoxH264Pref(targetMid,sessionDescription),sessionDescription.sdp=self._setSDPCodecParams(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPUnknownAptRtx(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPCodecs(targetMid,sessionDescription),sessionDescription.sdp=self._handleSDPConnectionSettings(targetMid,sessionDescription,"local"),sessionDescription.sdp=self._removeSDPREMBPackets(targetMid,sessionDescription),log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description updated ->"],sessionDescription.sdp),pc.setLocalDescription(new RTCSessionDescription(sessionDescription),function(){if(log.debug([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description has been set ->"],sessionDescription),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",sessionDescription.type,targetMid),sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER?pc.setAnswer="local":pc.setOffer="local",!self._enableIceTrickle&&!pc.gathered)return void log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description sending is halted to complete ICE gathering."]);self._sendChannelMessage({type:sessionDescription.type,sdp:self._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},function(error){log.error([targetMid,"RTCSessionDescription",sessionDescription.type,"Local description failed setting ->"],error),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)})},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._appKey?("function"==typeof showAll&&(callback=showAll,showAll=!1),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.GET_PEERS,showAll:showAll||!1}),self._trigger("getPeersStateChange",self.GET_PEERS_STATE.ENQUIRED,self._user.sid,null),log.log("Enquired server for peers within the realm"),void("function"==typeof callback&&self.once("getPeersStateChange",function(state,privilegedPeerId,peerList){callback(null,peerList)},function(state,privilegedPeerId,peerList){return state===self.GET_PEERS_STATE.RECEIVED}))):void log.warn("App key is not defined. Please authenticate again."):void log.warn("Please upgrade your key to privileged to use this function")},Skylink.prototype.introducePeer=function(sendingPeerId,receivingPeerId){var self=this;if(!self._isPrivileged)return log.warn("Please upgrade your key to privileged to use this function"),void self._trigger("introduceStateChange",self.INTRODUCE_STATE.ERROR,self._user.sid,sendingPeerId,receivingPeerId,"notPrivileged");self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.INTRODUCE,sendingPeerId:sendingPeerId,receivingPeerId:receivingPeerId}),self._trigger("introduceStateChange",self.INTRODUCE_STATE.INTRODUCING,self._user.sid,sendingPeerId,receivingPeerId,null),log.log("Introducing",sendingPeerId,"to",receivingPeerId)},Skylink.prototype.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};room&&"string"==typeof room?selectedRoom=room:room&&"object"==typeof room?mediaOptions=room:"function"==typeof room&&(callback=room),options&&"object"==typeof options?mediaOptions=options:"function"==typeof options&&(callback=options);var resolveAsErrorFn=function(error,tryRoom,readyState){log.error(error),"function"==typeof callback&&callback({room:tryRoom,errorCode:readyState||null,error: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("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.23",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;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,"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"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,self._useEdgeWebRTC=useEdgeWebRTC,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}),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})):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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"Network error occurred. (Status: "+xhr.status+")",errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom)},xhr.onprogress=function(){log.debug([null,"XMLHttpRequest",method,"Retrieving information and config from webserver. Url:"],url),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},Skylink.prototype._parseInfo=function(info){if(log.log("Parsing parameter from server",info),!info.pc_constraints&&!info.offer_constraints)return void this._trigger("readyStateChange",this.READY_STATE_CHANGE.ERROR,{status:200,content:info.info,errorCode:info.error},self._selectedRoom);log.debug("Peer connection constraints:",info.pc_constraints),log.debug("Offer constraints:",info.offer_constraints),this._key=info.cid,this._appKeyOwner=info.apiOwner,this._signalingServer=info.ipSigserver,this._isPrivileged=info.isPrivileged,this._autoIntroduce=info.autoIntroduce,this._user={uid:info.username,token:info.userCred,timeStamp:info.timeStamp,streams:[],info:{}},this._room={id:info.room_key,token:info.roomCred,startDateTime:info.start,duration:info.len,connection:{peerConstraints:JSON.parse(info.pc_constraints),peerConfig:null,offerConstraints:JSON.parse(info.offer_constraints),sdpConstraints:{mandatory:{OfferToReceiveAudio:!0,OfferToReceiveVideo:!0}},mediaConstraints:JSON.parse(info.media_constraints)}},this._socketPorts={"http:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,this._trigger("readyStateChange",this.READY_STATE_CHANGE.COMPLETED,null,this._selectedRoom),log.info("Parsed parameters from webserver. Ready for web-realtime communication")},Skylink.prototype._loadInfo=function(){var self=this,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!function(){try{var p=new window.RTCPeerConnection(null);return["object","function"].indexOf(typeof p.createOffer)>-1&&null!==p.createOffer}catch(e){return!1}}())return window.RTCPeerConnection&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);self._getCodecsSupport(function(error){return error?(log.error(error),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:error.message||error.toString(),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):0===Object.keys(self._currentCodecSupport.audio).length&&0===Object.keys(self._currentCodecSupport.video).length?(log.error("No audio/video codecs available to start connection."),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No API Path is found",errorCode:self.READY_STATE_CHANGE_ERROR.NO_PATH},self._selectedRoom)):(log.error("XMLHttpRequest not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"XMLHttpRequest not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_XMLHTTPREQUEST_SUPPORT},self._selectedRoom)):(log.error("Socket.io not loaded. Please load socket.io"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"Socket.io not found",errorCode:self.READY_STATE_CHANGE_ERROR.NO_SOCKET_IO},self._selectedRoom))},Skylink.prototype._initSelectedRoom=function(room,callback){var self=this;if("function"==typeof room||void 0===room)return void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null,useEdgeWebRTC:self._useEdgeWebRTC};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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,target:message.target,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._redirectHandler=function(message){if(log.log(["Server",null,message.type,"System action warning:"],{message:message.info,reason:message.reason,action:message.action}),message.action===this.SYSTEM_ACTION.REJECT)for(var key in this._peerConnections)this._peerConnections.hasOwnProperty(key)&&this._removePeer(key);"toClose"===message.reason&&(message.reason="toclose"),this._trigger("systemAction",message.action,message.info,message.reason)},Skylink.prototype._updateUserEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer updated userData:"],message.userData),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].userData=message.stamp}this._peerInformations[targetMid].userData=message.userData||{},this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._roomLockEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,message.type,"Room lock status:"],message.lock),this._trigger("roomLock",message.lock,targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._muteAudioEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's audio muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].audioMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.audioMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,message.type,"Peer does not have any user information"])},Skylink.prototype._muteVideoEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's video muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].videoMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.videoMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._streamEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Peer's stream status:"],message.status),this._peerInformations[targetMid]&&message.streamId?(this._streamsSession[targetMid]=this._streamsSession[targetMid]||{},"ended"===message.status&&(message.settings&&"object"==typeof message.settings&&void 0===this._streamsSession[targetMid][message.streamId]&&(this._streamsSession[targetMid][message.streamId]={audio:message.settings.audio,video:message.settings.video}),this._handleEndedStreams(targetMid,message.streamId))):log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._byeHandler=function(message){var targetMid=message.mid;(this._user||{}).sid!==targetMid?(log.log([targetMid,null,message.type,"Peer has left the room"]),this._removePeer(targetMid)):log.log([targetMid,null,message.type,"Self has left the room"])},Skylink.prototype._privateMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received private message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!0,targetPeerId:message.target,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._publicMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received public message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!1,targetPeerId:null,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._recordingEventHandler=function(message){var self=this;if(log.debug(["MCU","Recording",null,"Received recording message ->"],message),"on"===message.action)self._recordings[message.recordingId]||(log.debug(["MCU","Recording",message.recordingId,"Started recording"]),self._currentRecordingId=message.recordingId,self._recordings[message.recordingId]={active:!0,state:self.RECORDING_STATE.START,startedDateTime:(new Date).toISOString(),endedDateTime:null,mixingDateTime:null,links:null,error:null},self._recordingStartInterval=setTimeout(function(){log.log(["MCU","Recording",message.recordingId,"4 seconds has been recorded. Recording can be stopped now"]),self._recordingStartInterval=null},4e3),self._trigger("recordingState",self.RECORDING_STATE.START,message.recordingId,null,null));else if("off"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,'Received request of "off" but the session is empty']);self._currentRecordingId=null,self._recordingStartInterval&&(clearTimeout(self._recordingStartInterval),log.warn(["MCU","Recording",message.recordingId,"Recording stopped abruptly before 4 seconds"]),self._recordingStartInterval=null),log.debug(["MCU","Recording",message.recordingId,"Stopped recording"]),self._recordings[message.recordingId].active=!1,self._recordings[message.recordingId].state=self.RECORDING_STATE.STOP,self._recordings[message.recordingId].endedDateTime=(new Date).toISOString(),self._trigger("recordingState",self.RECORDING_STATE.STOP,message.recordingId,null,null)}else if("url"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,"Received URL but the session is empty"]);var links={};if(Array.isArray(message.urls))for(var i=0;i"],recordingError);log.error(["MCU","Recording",message.recordingId,"Recording failure ->"],recordingError),self._recordings[message.recordingId].state=self.RECORDING_STATE.ERROR,self._recordings[message.recordingId].error=recordingError,self._recordings[message.recordingId].active&&(log.debug(["MCU","Recording",message.recordingId,"Stopped recording abruptly"]),self._recordings[message.recordingId].active=!1),self._trigger("recordingState",self.RECORDING_STATE.ERROR,message.recordingId,null,recordingError)}},Skylink.prototype._inRoomHandler=function(message){var self=this;log.log(["Server",null,message.type,"User is now in the room and functionalities are now available. Config received:"],message.pc_config),self._room.connection.peerConfig=self._setIceServers(message.pc_config),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.ENFORCE_OFFERER?2e15:-2e15),self._trigger("peerJoined",self._user.sid,self.getPeerInfo(),!0),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,self._user.sid);var streamId=null;self._streams.screenshare&&self._streams.screenshare.stream?(streamId=self._streams.screenshare.stream.id||self._streams.screenshare.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.screenshare.stream,!0,self.getPeerInfo(),!0,streamId)):self._streams.userMedia&&self._streams.userMedia.stream&&(streamId=self._streams.userMedia.stream.id||self._streams.userMedia.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.userMedia.stream,!0,self.getPeerInfo(),!1,streamId));var enterMsg={type:self._SIG_MESSAGE_TYPE.ENTER,mid:self._user.sid,rid:self._room.id,agent:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._enterHandler=function(message){var self=this,targetMid=message.mid,isNewPeer=!1,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),receiveOnly:self.getPeerInfo().config.receiveOnly,os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg),isNewPeer&&self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._restartHandler=function(message){var self=this,targetMid=message.mid,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg)}};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._offerHandler=function(message){var self=this,targetMid=message.mid,pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for offer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}log.log([targetMid,null,message.type,"Received offer from peer. Session description:"],clone(message));var offer={type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};return log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],offer),offer.sdp=self._removeSDPFilteredCandidates(targetMid,offer),offer.sdp=self._setSDPCodec(targetMid,offer),offer.sdp=self._setSDPBitrate(targetMid,offer),offer.sdp=self._setSDPCodecParams(targetMid,offer),offer.sdp=self._removeSDPCodecs(targetMid,offer),offer.sdp=self._removeSDPREMBPackets(targetMid,offer),offer.sdp=self._handleSDPConnectionSettings(targetMid,offer,"remote"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,null,message.type,'Peer connection state is not in "stable" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.resend}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),void pc.setRemoteDescription(new RTCSessionDescription(offer),function(){log.debug([targetMid,"RTCSessionDescription",message.type,"Remote description set"]),pc.setOffer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.OFFER,targetMid),self._addIceCandidateFromQueue(targetMid),self._doAnswer(targetMid)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,offer:offer})}))},Skylink.prototype._candidateHandler=function(message){var targetMid=message.mid;if(!message.candidate&&!message.id)return void log.warn([targetMid,"RTCIceCandidate",null,"Received invalid ICE candidate message ->"],message);var canId="can-"+(new Date).getTime(),candidateType=message.candidate.split(" ")[7]||"",candidate=new RTCIceCandidate({sdpMLineIndex:message.label,candidate:message.candidate,sdpMid:message.id});if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Received ICE candidate ->"],candidate),this._peerEndOfCandidatesCounter[targetMid]=this._peerEndOfCandidatesCounter[targetMid]||{},this._peerEndOfCandidatesCounter[targetMid].len=this._peerEndOfCandidatesCounter[targetMid].len||0,this._peerEndOfCandidatesCounter[targetMid].hasSet=!1,this._peerEndOfCandidatesCounter[targetMid].len++,this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.RECEIVED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!this._peerConnections[targetMid]||this._peerConnections[targetMid].signalingState===this.PEER_CONNECTION_STATE.CLOSED)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed.")),void this._signalingEndOfCandidates(targetMid);if(this._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._forceTURN)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping received ICE candidate as it matches ICE candidate filtering flag ->"],candidate),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Dropping of processing ICE candidate as it matches ICE candidate filtering flag.")),void this._signalingEndOfCandidates(targetMid);log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Not dropping received ICE candidate as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured ->"],candidate)}this._peerConnections[targetMid].remoteDescription&&this._peerConnections[targetMid].remoteDescription.sdp&&this._peerConnections[targetMid].localDescription&&this._peerConnections[targetMid].localDescription.sdp?this._addIceCandidate(targetMid,canId,candidate):this._addIceCandidateToQueue(targetMid,canId,candidate),this._signalingEndOfCandidates(targetMid),this._gatheredCandidates[targetMid]||(this._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),this._gatheredCandidates[targetMid].receiving[candidateType].push({sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex,candidate:candidate.candidate})},Skylink.prototype._answerHandler=function(message){var self=this,targetMid=message.mid;log.log([targetMid,null,message.type,"Received answer from peer. Session description:"],clone(message));var pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for answer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}var answer={type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};return log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],answer),answer.sdp=self._removeSDPFilteredCandidates(targetMid,answer),answer.sdp=self._setSDPCodec(targetMid,answer),answer.sdp=self._setSDPBitrate(targetMid,answer),answer.sdp=self._setSDPCodecParams(targetMid,answer),answer.sdp=self._removeSDPCodecs(targetMid,answer),answer.sdp=self._removeSDPREMBPackets(targetMid,answer),answer.sdp=self._handleSDPConnectionSettings(targetMid,answer,"remote"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?void log.warn([targetMid,null,message.type,'Peer connection state is not in "have-local-offer" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.restart}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),void pc.setRemoteDescription(new RTCSessionDescription(answer),function(){log.debug([targetMid,null,message.type,"Remote description set"]),pc.setAnswer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ANSWER,targetMid),self._addIceCandidateFromQueue(targetMid),self._peerMessagesStamps[targetMid]&&(self._peerMessagesStamps[targetMid].hasRestart=!1),self._dataChannels[targetMid]&&(-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))},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,answer:answer})}))},Skylink.prototype._isLowerThanVersion=function(agentVer,requiredVer){for(var partsA=(agentVer||"").split("."),partsB=(requiredVer||"").split("."),i=0;i0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for sendStream() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream);else{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"===window.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"===window.webrtcDetectedBrowser?(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio=getUserMediaAudioSettings):useMediaSource.indexOf("audio")>-1&&useMediaSource.indexOf("tab")>-1&&(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio={})),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if(hasDefaultAudioTrack||!enableAudioSettings)return void self._onStreamAccessSuccess(stream,settings,!0,!1);settings.getUserMediaSettings.audio=getUserMediaAudioSettings,navigator.getUserMedia({audio:getUserMediaAudioSettings},function(audioStream){try{audioStream.addTrack(stream.getVideoTracks()[0]),self.once("mediaAccessSuccess",function(){self._streams.screenshare.streamClone=stream},function(stream,isScreensharing){return isScreensharing}),self._onStreamAccessSuccess(audioStream,settings,!0,!1)}catch(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.shareScreen)},Skylink.prototype.stopScreen=function(){this._streams.screenshare&&(this._stopStreams({screenshare:!0}),this._inRoom&&(this._streams.userMedia&&this._streams.userMedia.stream&&(this._trigger("incomingStream",this._user.sid,this._streams.userMedia.stream,!0,this.getPeerInfo(),!1,this._streams.userMedia.stream.id||this._streams.userMedia.stream.label),this._trigger("peerUpdated",this._user.sid,this.getPeerInfo(),!0)),this._refreshPeerConnection(Object.keys(this._peerConnections),{},!1)))},Skylink.prototype._muteStreams=function(){var self=this,hasVideo=!1,hasAudio=!1,muteFn=function(stream){for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",self._streamsMutedSettings),{hasVideo:hasVideo,hasAudio:hasAudio}},Skylink.prototype._stopStreams=function(options){var self=this,stopFn=function(stream){var streamId=stream.id||stream.label;log.debug([null,"MediaStream",streamId,"Stopping Stream ->"],stream);try{for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",options)},Skylink.prototype._parseStreamSettings=function(options){var settings={settings:{audio:!1,video:!1},mutedSettings:{shouldAudioMuted:!1,shouldVideoMuted:!1},getUserMediaSettings:{audio:!1,video:!1}};return options.audio&&(settings.settings.audio={stereo:!1,exactConstraints:!!options.useExactConstraints,echoCancellation:!0},settings.getUserMediaSettings.audio={echoCancellation:!0},"object"==typeof options.audio&&("boolean"==typeof options.audio.stereo&&(settings.settings.audio.stereo=options.audio.stereo),"boolean"==typeof options.audio.useinbandfec&&(settings.settings.audio.useinbandfec=options.audio.useinbandfec),"boolean"==typeof options.audio.usedtx&&(settings.settings.audio.usedtx=options.audio.usedtx),"number"==typeof options.audio.maxplaybackrate&&options.audio.maxplaybackrate>=8e3&&options.audio.maxplaybackrate<=48e3&&(settings.settings.audio.maxplaybackrate=options.audio.maxplaybackrate),"boolean"==typeof options.audio.mute&&(settings.mutedSettings.shouldAudioMuted=options.audio.mute),"edge"!==window.webrtcDetectedBrowser&&("boolean"==typeof options.audio.echoCancellation&&(settings.settings.audio.echoCancellation=options.audio.echoCancellation,settings.getUserMediaSettings.audio.echoCancellation=options.audio.echoCancellation),Array.isArray(options.audio.optional)&&(settings.settings.audio.optional=clone(options.audio.optional),settings.getUserMediaSettings.audio.optional=clone(options.audio.optional)),options.audio.deviceId&&"string"==typeof options.audio.deviceId&&"firefox"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,settings.getUserMediaSettings.audio.deviceId=options.useExactConstraints?{exact:options.audio.deviceId}:{ideal:options.audio.deviceId}))),"edge"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio=!0)),options.video&&(settings.settings.video={resolution:clone(this.VIDEO_RESOLUTION.VGA),screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video={},"object"==typeof options.video?("boolean"==typeof options.video.mute&&(settings.mutedSettings.shouldVideoMuted=options.video.mute),Array.isArray(options.video.optional)&&(settings.settings.video.optional=clone(options.video.optional),settings.getUserMediaSettings.video.optional=clone(options.video.optional)),options.video.deviceId&&"string"==typeof options.video.deviceId&&"firefox"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,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&&!self._isUsingPlugin)&&(settings.settings.video.frameRate=options.video.frameRate,settings.getUserMediaSettings.video.frameRate="object"==typeof settings.settings.video.frameRate?settings.settings.video.frameRate:options.useExactConstraints?{exact:settings.settings.video.frameRate}:{max:settings.settings.video.frameRate}),options.video.facingMode&&["string","object"].indexOf(typeof options.video.facingMode)>-1&&self._isUsingPlugin&&(settings.settings.video.facingMode=options.video.facingMode,settings.getUserMediaSettings.video.facingMode="object"==typeof settings.settings.video.facingMode?settings.settings.video.facingMode:options.useExactConstraints?{exact:settings.settings.video.facingMode}:{max:settings.settings.video.facingMode})):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"===window.webrtcDetectedBrowser&&(settings.settings.video={screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video=!0)),settings},Skylink.prototype._onStreamAccessSuccess=function(stream,settings,isScreenSharing,isAudioFallback){var self=this,streamId=stream.id||stream.label,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(window.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"===window.webrtcDetectedBrowser?stream.endedInterval=setInterval(function(){void 0===stream.recordedTime&&(stream.recordedTime=0),stream.recordedTime===stream.currentTime?(clearInterval(stream.endedInterval),self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])):stream.recordedTime=stream.currentTime},1e3):stream.onended=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},settings.settings.audio&&0===stream.getAudioTracks().length||settings.settings.video&&0===stream.getVideoTracks().length){var tracksNotSameError="Expected audio tracks length with "+(settings.settings.audio?"1":"0")+" and video tracks length with "+(settings.settings.video?"1":"0")+" but received audio tracks length with "+stream.getAudioTracks().length+" and video tracks length with "+stream.getVideoTracks().length;log.warn([null,"MediaStream",streamId,tracksNotSameError]);var requireAudio=!!settings.settings.audio,requireVideo=!!settings.settings.video;settings.settings.audio&&0===stream.getAudioTracks().length&&(settings.settings.audio=!1),settings.settings.video&&0===stream.getVideoTracks().length&&(settings.settings.video=!1),self._trigger("mediaAccessFallback",{error:new Error(tracksNotSameError),diff:{video:{expected:requireVideo?1:0,received:stream.getVideoTracks().length},audio:{expected:requireAudio?1:0,received:stream.getAudioTracks().length}}},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKED,!!isScreenSharing,!!isAudioFallback,streamId)}self._streams[isScreenSharing?"screenshare":"userMedia"]={stream:stream,settings:settings.settings,constraints:settings.getUserMediaSettings},self._muteStreams(),self._trigger("mediaAccessSuccess",stream,!!isScreenSharing,!!isAudioFallback,streamId)},Skylink.prototype._onStreamAccessError=function(error,settings,isScreenSharing){var self=this;if(!isScreenSharing&&settings.settings.audio&&settings.settings.video&&self._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},function(error){log.error("Failed fallbacking to retrieve audio only Stream ->",error),self._trigger("mediaAccessError",error,!1,!0),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.ERROR,!1,!0)});log.error("Failed retrieving "+(isScreenSharing?"screensharing":"camera")+" Stream ->",error),self._trigger("mediaAccessError",error,!!isScreenSharing,!1)},Skylink.prototype._onRemoteStreamAdded=function(targetMid,stream,isScreenSharing){var self=this;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1)},Skylink.prototype._addLocalMediaStreams=function(peerId){var self=this;try{log.log([peerId,null,null,"Adding local stream"]);var pc=self._peerConnections[peerId],offerToReceiveAudio=(self._peerInformations[peerId],self._peerInformations[peerId],!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-1?log.warn([peerId,null,null,"Not re-adding stream as LocalMediaStream is already added"],error):log.error([peerId,null,null,"Failed adding local stream"],error)}},Skylink.prototype._handleEndedStreams=function(peerId,checkStreamId){var self=this;self._streamsSession[peerId]=self._streamsSession[peerId]||{};var renderEndedFn=function(streamId){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){var codecsList=sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codecName+"/"+(samplingRate?samplingRate+("audio"===type?"[/]*.*":".*"):".*")+"\r\n","gi"));if(Array.isArray(codecsList)&&codecsList.length>0)for(var i=0;i0){for(var fmtpParts=(fmtpLine[0].split("a=fmtp:"+payload+" ")[1]||"").replace(/ /g,"").replace(/\r\n/g,"").split(";"),j=0;j0){if(0===sdpLines[i].indexOf("m="))break;0===sdpLines[i].indexOf("c=")?cLineIndex=i:0!==sdpLines[i].indexOf("b=AS:")&&0!==sdpLines[i].indexOf("b:TIAS:")||(sdpLines.splice(i,1),i--)}return"number"==typeof bw&&bw>0?-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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(this._peerInformations[targetMid],this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],compareB.join(" ")),sdpLines.splice(j,0,compareB.join(" ")),j++,mLineIndex++)}for(;this._sdpSessions[targetMid].remote.mLines[mLineIndex+1];){mLineIndex++;var appendIndex=sdpLines.length;sdpLines[appendIndex-1].replace(/\s/gi,"")||(appendIndex-=1);var parts=(this._sdpSessions[targetMid].remote.mLines[mLineIndex]||"").split(" ");parts[1]=0,log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending later rejected m= line ->"],parts.join(" ")),sdpLines.splice(appendIndex,0,parts.join(" "))}}return"edge"!==window.webrtcDetectedBrowser||sessionDescription.type!==this.HANDSHAKE_PROGRESS.OFFER||sdpLines[sdpLines.length-1].replace(/\s/gi,"")||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing last empty space for Edge browsers"]),sdpLines.splice(sdpLines.length-1,1)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "'+codec+'" as it does not exists.']);for(var i=0;i'],payload),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=fmtp:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:\\d+ rtx\\/\\d+\\r\\na=fmtp:\\d+ apt="+payload+"\\r\\n","g"),"");for(var sdpLines=sessionDescription.sdp.split("\r\n"),j=0;j=3&&parts.splice(parts.indexOf(payload),1),sdpLines[j]=parts.join(" ");break}sessionDescription.sdp=sdpLines.join("\r\n")}};return this._disableVideoFecCodecs&&(this._hasMCU?log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "ulpfec" or "red" codecs as connected to MCU to prevent connectivity issues.']):(parseFn("video","red"),parseFn("video","ulpfec"))),this._disableComfortNoiseCodec&&audioSettings&&"object"==typeof audioSettings&&audioSettings.stereo&&parseFn("audio","CN"),"edge"===window.webrtcDetectedBrowser&&"edge"!==(((this._peerInformations[targetMid]||{}).agent||{}).name||"unknown").name&&(sessionDescription.sdp=sessionDescription.sdp.replace(/a=rtcp-fb:.*\ x-message\ .*\r\n/gi,"")),sessionDescription.sdp},Skylink.prototype._removeSDPREMBPackets=function(targetMid,sessionDescription){return this._disableREMB?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing REMB packets."]),sessionDescription.sdp.replace(/a=rtcp-fb:\d+ goog-remb\r\n/g,"")):sessionDescription.sdp},Skylink.prototype._getSDPSelectedCodec=function(targetMid,sessionDescription,type,beSilentOnLogs){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},Skylink.prototype._removeSDPFilteredCandidates=function(targetMid,sessionDescription){return"MCU"===targetMid&&sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER&&"firefox"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=sessionDescription.sdp.replace(/ generation 0/g,""),sessionDescription.sdp=sessionDescription.sdp.replace(/ udp /g," UDP ")),this._forceTURN&&this._hasMCU?(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not filtering ICE candidates as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured"]),sessionDescription.sdp):(this._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._filterCandidatesType.relay&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "relay" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*relay.*\r\n/g,"")),sessionDescription.sdp)},Skylink.prototype._getCodecsSupport=function(callback){var self=this;if(self._currentCodecSupport)return void callback(null);self._currentCodecSupport={audio:{},video:{}};try{if("edge"===window.webrtcDetectedBrowser){for(var codecs=RTCRtpSender.getCapabilities().codecs,i=0;i-1&&codecs[i].name){var codec=codecs[i].name.toLowerCase();self._currentCodecSupport[codecs[i].kind][codec]=codecs[i].clockRate+(codecs[i].numChannels>1?"/"+codecs[i].numChannels:"")}callback(null)}else{var pc=new RTCPeerConnection(null),offerConstraints={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveVideo:!0,OfferToReceiveAudio:!0}});try{var channel=pc.createDataChannel("test");self._binaryChunkType=channel.binaryType||self._binaryChunkType,self._binaryChunkType=self._binaryChunkType.toLowerCase().indexOf("array")>-1?self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER:self._binaryChunkType;for(var prop in self.DATA_TRANSFER_DATA_TYPE)if(self.DATA_TRANSFER_DATA_TYPE.hasOwnProperty(prop)&&self._binaryChunkType.toLowerCase()===self.DATA_TRANSFER_DATA_TYPE[prop].toLowerCase()){self._binaryChunkType=self.DATA_TRANSFER_DATA_TYPE[prop];break}}catch(e){}pc.createOffer(function(offer){ +for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",i=0;i"],sdpLines[i]),self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE&&bundleLineIndex>-1&&0===mLineIndex&&("remote"===direction?sessionDescription.type===this.HANDSHAKE_PROGRESS.OFFER:sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER)){log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not removing rejected m="+mediaType+" line ->"],sdpLines[i]),settings.connection[mediaType]=!0,["audio","video"].indexOf(mediaType)>-1&&(settings.direction[mediaType].send=!1,settings.direction[mediaType].receive=!1);continue}if("edge"===window.webrtcDetectedBrowser){sdpLines.splice(i,1),i--;continue}if("remote"===direction||sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER){var parts=sdpLines[i].split(" ");parts[1]=0,sdpLines[i]=parts.join(" ");continue}}if("remote"!==direction||0!==sdpLines[i].indexOf("a=candidate:")||self.getPeerInfo(targetMid).config.enableIceTrickle||sdpLines[i+1]&&(0===sdpLines[i+1].indexOf("a=candidate:")||0===sdpLines[i+1].indexOf("a=end-of-candidates"))||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]),sdpLines.splice(i+1,0,"a=end-of-candidates"),i++),mediaType)if(settings.connection[mediaType]){if(0===sdpLines[i].indexOf("a=mid:"))bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||"");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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"undefined"!=typeof exports?module.exports={Skylink:Skylink,SkylinkLogs:SkylinkLogs}:globals?(globals.Skylink=Skylink,globals.SkylinkLogs=SkylinkLogs):window&&(window.Skylink=Skylink,window.SkylinkLogs=SkylinkLogs)}(this); \ No newline at end of file diff --git a/publish/skylink.debug.js b/publish/skylink.debug.js index 30c201755..439880dcb 100644 --- a/publish/skylink.debug.js +++ b/publish/skylink.debug.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.23 - Thu Jul 13 2017 18:37:09 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.23 - Fri Jul 14 2017 22:08:48 GMT+0800 (+08) */ (function(globals) { @@ -10154,8 +10154,9 @@ Skylink.prototype.generateUUID = function() { * @param {JSON} [options.codecParams.audio.opus]
    * Note that this is only applicable to OPUS audio codecs with a sampling rate of 48000 Hz (hertz). *
    The OPUS audio codec parameters to configure. - * @param {Boolean} [options.codecParams.audio.opus.stereo] The flag if OPUS audio codec stereo band - * should be configured for sending encoded audio data. + * @param {Boolean} [options.codecParams.audio.opus.stereo] The flag if OPUS audio codec is able to decode or receive stereo packets. + * When not provided, the default browser configuration is used. + * @param {Boolean} [options.codecParams.audio.opus.sprop-stereo] The flag if OPUS audio codec is sending stereo packets. * When not provided, the default browser configuration is used. * @param {Boolean} [options.codecParams.audio.opus.usedtx]
    * Note that this feature might not work depending on the browser support and implementation.
    @@ -10554,6 +10555,8 @@ Skylink.prototype.init = function(options, callback) { codecParams.audio.opus = { stereo: typeof options.codecParams.audio.opus.stereo === 'boolean' ? options.codecParams.audio.opus.stereo : null, + 'sprop-stereo': typeof options.codecParams.audio.opus['sprop-stereo'] === 'boolean' ? + options.codecParams.audio.opus['sprop-stereo'] : null, usedtx: typeof options.codecParams.audio.opus.usedtx === 'boolean' ? options.codecParams.audio.opus.usedtx : null, useinbandfec: typeof options.codecParams.audio.opus.useinbandfec === 'boolean' ? @@ -17708,7 +17711,8 @@ Skylink.prototype._setSDPCodecParams = function(targetMid, sessionDescription) { // RFC: https://tools.ietf.org/html/draft-ietf-payload-rtp-opus-11 parseFn('audio', self.AUDIO_CODEC.OPUS, 48000, (function () { var opusOptions = {}; - var audioSettings = self.getPeerInfo().settings.audio; + var audioSettings = self._streams.screenshare ? self._streams.screenshare.settings.audio : + (self._streams.userMedia ? self._streams.userMedia.settings.audio : {}); audioSettings = audioSettings && typeof audioSettings === 'object' ? audioSettings : {}; if (typeof self._codecParams.audio.opus.stereo === 'boolean') { opusOptions.stereo = self._codecParams.audio.opus.stereo; diff --git a/publish/skylink.min.js b/publish/skylink.min.js index 33c3967e8..31598a71a 100644 --- a/publish/skylink.min.js +++ b/publish/skylink.min.js @@ -1,12 +1,12 @@ -/*! skylinkjs - v0.6.23 - 2017-07-13 */ +/*! skylinkjs - v0.6.23 - 2017-07-14 */ !function(globals){"use strict";function Skylink(){this._enableDataChannel=!0,this._dataChannels={},this._dataTransfers={},this._dataStreams={},this._peerCandidatesQueue={},this._peerEndOfCandidatesCounter={},this._gatheredCandidates={},this._filterCandidatesType={host:!1,srflx:!1,relay:!1},this._enableIceTrickle=!0,this._enableSTUN=!0,this._enableTURN=!0,this._usePublicSTUN=!0,this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},this._isUsingPlugin=!1,this._TURNTransport="any",this._peerInformations={},this._user=null,this._userData="",this._peerPriorityWeight=0,this._autoIntroduce=!0,this._isPrivileged=!1,this._peerList=null,this._selectedRoom=null,this._roomLocked=!1,this._inRoom=!1,this._EVENTS={},this._onceEvents={},this._timestamp={socketMessage:null,shareScreen:null,refreshConnection:null,getUserMedia:null,lastRestart:null},this._throttlingTimeouts={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},this._throttlingShouldThrowError=!1,this._socketSession={},this._socketMessageQueue=[],this._socketMessageTimeout=null,this._socketPorts={"http:":[80,3e3],"https:":[443,3443]},this._channelOpen=!1,this._signalingServer=null,this._signalingServerProtocol=window.location.protocol,this._signalingServerPort=null,this._socket=null,this._socketTimeout=2e4,this._socketUseXDR=!1,this._enableIceRestart="firefox"!==window.webrtcDetectedBrowser||window.webrtcDetectedVersion>=48,this._hasMCU=!1,this._forceSSL=!1,this._forceTURNSSL=!1,this._forceTURN=!1,this._path=null,this._roomServer="//api.temasys.io",this._appKey=null,this._defaultRoom=null,this._roomStart=null,this._roomDuration=null,this._roomCredentials=null,this._readyState=0,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._audioFallback=!1,this._streams={userMedia:null,screenshare:null},this._streamsDefaultSettings={userMedia:{audio:{stereo:!1},video:{resolution:{width:640,height:480},frameRate:50}},screenshare:{video:!0}},this._streamsMutedSettings={audioMuted:!1,videoMuted:!1},this._streamsBandwidthSettings={googleX:{},bAS:{}},this._streamsStoppedCbs={},this._streamsSession={},this._selectedAudioCodec="auto",this._selectedVideoCodec="auto",this._disableVideoFecCodecs=!1,this._disableComfortNoiseCodec=!1,this._disableREMB=!1,this._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},this._publishOnly=!1,this._parentId=null,this._recordings={},this._currentRecordingId=!1,this._recordingStartInterval=null,this._mcuUseRenegoRestart=!1,this._iceServer=null,this._socketServer=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType="firefox"===window.webrtcDetectedBrowser?this.DATA_TRANSFER_DATA_TYPE.BLOB:this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={},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;var clone=function(obj){if(null===obj||"object"!=typeof obj)return obj;var copy=function(data){var copy=data.constructor();for(var attr in data)data.hasOwnProperty(attr)&&(copy[attr]=data[attr]);return copy};if("object"==typeof obj&&!Array.isArray(obj))try{return JSON.parse(JSON.stringify(obj))}catch(err){return copy(obj)}return copy(obj)};Skylink.prototype.DATA_CHANNEL_STATE={CONNECTING:"connecting",OPEN:"open",CLOSING:"closing",CLOSED:"closed",ERROR:"error",CREATE_ERROR:"createError",BUFFERED_AMOUNT_LOW:"bufferedAmountLow",SEND_MESSAGE_ERROR:"sendMessageError"},Skylink.prototype.DATA_CHANNEL_TYPE={MESSAGING:"messaging",DATA:"data"},Skylink.prototype.DATA_CHANNEL_MESSAGE_ERROR={MESSAGE:"message",TRANSFER:"transfer"},Skylink.prototype._createDataChannel=function(peerId,dataChannel,bufferThreshold,createAsMessagingChannel){var self=this,channelName=(self._user&&self._user.sid?self._user.sid:"-")+"_"+peerId,channelType=createAsMessagingChannel?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,channelProp=channelType===self.DATA_CHANNEL_TYPE.MESSAGING?"main":channelName;if(!self._user)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as User does not have Room session"]);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as Peer connection does not exists"]);if(dataChannel&&"object"==typeof dataChannel?channelName=dataChannel.label:"string"==typeof dataChannel&&(channelName=dataChannel,dataChannel=null),!dataChannel)try{dataChannel=self._peerConnections[peerId].createDataChannel(channelName,{reliable:!0,ordered:!0})}catch(error){return log.error([peerId,"RTCDataChannel",channelProp,"Failed creating Datachannel ->"],error),void self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CREATE_ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))}self._dataChannels[peerId]?self._dataChannels[peerId].main&&self._dataChannels[peerId].main.channel.label===channelName&&(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING):(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING,self._dataChannels[peerId]={},log.debug([peerId,"RTCDataChannel",channelProp,"initializing main DataChannel"])),dataChannel.onerror=function(evt){var channelError=evt.error||evt;log.error([peerId,"RTCDataChannel",channelProp,"Datachannel has an exception ->"],channelError),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,channelError,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onbufferedamountlow=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel buffering data transfer low"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.BUFFERED_AMOUNT_LOW,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onmessage=function(event){self._processDataChannelData(event.data,peerId,channelName,channelType)};var onOpenHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has opened"]),dataChannel.bufferedAmountLowThreshold=bufferThreshold||0,self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.OPEN,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))};dataChannel.readyState===self.DATA_CHANNEL_STATE.OPEN?setTimeout(onOpenHandlerFn,1):(self._trigger("dataChannelState",dataChannel.readyState,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),dataChannel.onopen=onOpenHandlerFn);var onCloseHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has closed"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSED,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),self._peerConnections[peerId]&&self._peerConnections[peerId].remoteDescription&&self._peerConnections[peerId].remoteDescription.sdp&&(-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"===window.webrtcDetectedBrowser){var hasTriggeredClose=!1,timeBlockAfterClosing=0;dataChannel.onclose=function(){hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())};var onFFClosed=setInterval(function(){dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSED||hasTriggeredClose||5===timeBlockAfterClosing?(clearInterval(onFFClosed),hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())):dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSING&&timeBlockAfterClosing++},1e3)}else dataChannel.onclose=onCloseHandlerFn;channelType===self.DATA_CHANNEL_TYPE.MESSAGING?self._dataChannels[peerId].main={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}:self._dataChannels[peerId][channelName]={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}},Skylink.prototype._getDataChannelBuffer=function(peerId,channelProp){if("object"==typeof peerId)return{bufferedAmountLow:"number"==typeof peerId.bufferedAmountLow?peerId.bufferedAmountLow:parseInt(peerId.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof peerId.bufferedAmountLowThreshold?peerId.bufferedAmountLowThreshold:parseInt(peerId.bufferedAmountLowThreshold,10)||0};if(!(this._dataChannels[peerId]&&this._dataChannels[peerId][channelProp]&&this._dataChannels[peerId][channelProp].channel))return{bufferedAmountLow:0,bufferedAmountLowThreshold:0};var channel=this._dataChannels[peerId][channelProp].channel;return{bufferedAmountLow:"number"==typeof channel.bufferedAmountLow?channel.bufferedAmountLow:parseInt(channel.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof channel.bufferedAmountLowThreshold?channel.bufferedAmountLowThreshold:parseInt(channel.bufferedAmountLowThreshold,10)||0}},Skylink.prototype._sendMessageToDataChannel=function(peerId,data,channelProp,doNotConvert){var self=this;if(channelProp&&channelProp!==peerId||(channelProp="main"),!("object"==typeof data&&data||data&&"string"==typeof data))return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping invalid data ->"],data);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Peer connection does not exists or is closed ->"],data);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Datachannel connection does not exists ->"],data);var channelName=self._dataChannels[peerId][channelProp].channelName,channelType=self._dataChannels[peerId][channelProp].channelType,readyState=self._dataChannels[peerId][channelProp].channel.readyState,messageType="object"==typeof data&&data.type===self._DC_PROTOCOL_TYPE.MESSAGE?self.DATA_CHANNEL_MESSAGE_ERROR.MESSAGE:self.DATA_CHANNEL_MESSAGE_ERROR.TRANSFER;if(readyState!==self.DATA_CHANNEL_STATE.OPEN){var notOpenError='Failed sending message as Datachannel connection state is not opened. Current readyState is "'+readyState+'"';throw log.error([peerId,"RTCDataChannel",channelProp,notOpenError+" ->"],data),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,new Error(notOpenError),channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),new Error(notOpenError)}try{doNotConvert||"object"!=typeof data?(log.debug([peerId,"RTCDataChannel",channelProp,"Sending data with size ->"],data.size||data.length||data.byteLength),self._dataChannels[peerId][channelProp].channel.send(data)):(log.debug([peerId,"RTCDataChannel",channelProp,'Sending "'+data.type+'" protocol message ->'],data),self._dataChannels[peerId][channelProp].channel.send(JSON.stringify(data)))}catch(error){throw log.error([peerId,"RTCDataChannel",channelProp,"Failed sending "+(doNotConvert||"object"!=typeof data?"data":'"'+data.type+'" protocol message')+" ->"],error),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,error,channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),error}},Skylink.prototype._closeDataChannel=function(peerId,channelProp){var self=this;if(!self._dataChannels[peerId])return void log.warn([peerId,"RTCDataChannel",channelProp||null,"Aborting closing Datachannels as Peer connection does not have Datachannel sessions"]);var closeFn=function(rChannelProp){var channelName=self._dataChannels[peerId][rChannelProp].channelName,channelType=self._dataChannels[peerId][rChannelProp].channelType;self._dataChannels[peerId][rChannelProp].readyState!==self.DATA_CHANNEL_STATE.CLOSED&&(log.debug([peerId,"RTCDataChannel",channelProp,"Closing Datachannel"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSING,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(peerId,rChannelProp)),self._dataChannels[peerId][rChannelProp].channel.close(),delete self._dataChannels[peerId][rChannelProp])};if(channelProp){if(!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Aborting closing Datachannel as it does not exists"]);closeFn(channelProp)}else for(var channelNameProp in self._dataChannels)self._dataChannels[peerId].hasOwnProperty(channelNameProp)&&self._dataChannels[peerId][channelNameProp]&&closeFn(channelNameProp)},Skylink.prototype.DATA_TRANSFER_DATA_TYPE={BINARY_STRING:"binaryString",ARRAY_BUFFER:"arrayBuffer",BLOB:"blob",STRING:"string"},Skylink.prototype._CHUNK_FILE_SIZE=49152,Skylink.prototype._MOZ_CHUNK_FILE_SIZE=12288,Skylink.prototype._BINARY_FILE_SIZE=65456,Skylink.prototype._MOZ_BINARY_FILE_SIZE=16384,Skylink.prototype._CHUNK_DATAURL_SIZE=1212,Skylink.prototype._base64ToBlob=function(dataURL){for(var byteString=atob(dataURL),ab=new ArrayBuffer(byteString.length),ia=new Uint8Array(ab),j=0;jchunkSize){for(;blobByteSize-1>endCount;)endCount=startCount+chunkSize,chunksArray.push(blob.slice(startCount,endCount)),startCount+=chunkSize;blobByteSize-(startCount+1)>0&&chunksArray.push(blob.slice(startCount,blobByteSize-1))}else chunksArray.push(blob);return chunksArray},Skylink.prototype._chunkDataURL=function(dataURL,chunkSize){var outputStr=dataURL,dataURLArray=[],startCount=0,endCount=0,dataByteSize=dataURL.size||dataURL.length;if(dataByteSize>chunkSize){for(;dataByteSize-1>endCount;)endCount=startCount+chunkSize,dataURLArray.push(outputStr.slice(startCount,endCount)),startCount+=chunkSize;dataByteSize-(startCount+1)>0&&chunksArray.push(outputStr.slice(startCount,dataByteSize-1))}else dataURLArray.push(outputStr);return dataURLArray},Skylink.prototype.DT_PROTOCOL_VERSION="0.1.3",Skylink.prototype.DATA_TRANSFER_TYPE={UPLOAD:"upload",DOWNLOAD:"download"},Skylink.prototype.DATA_TRANSFER_SESSION_TYPE={BLOB:"blob",DATA_URL:"dataURL"},Skylink.prototype.DATA_TRANSFER_STATE={UPLOAD_REQUEST:"request",UPLOAD_STARTED:"uploadStarted",DOWNLOAD_STARTED:"downloadStarted",REJECTED:"rejected",CANCEL:"cancel",ERROR:"error",UPLOADING:"uploading",DOWNLOADING:"downloading",UPLOAD_COMPLETED:"uploadCompleted",DOWNLOAD_COMPLETED:"downloadCompleted",USER_REJECTED:"userRejected",USER_UPLOAD_REQUEST:"userRequest",START_ERROR:"startError"},Skylink.prototype.DATA_STREAM_STATE={SENDING_STARTED:"sendStart",SENDING_STOPPED:"sendStop",RECEIVING_STARTED:"receiveStart",RECEIVING_STOPPED:"receiveStop",RECEIVED:"received",SENT:"sent",ERROR:"error",START_ERROR:"startError"},Skylink.prototype._DC_PROTOCOL_TYPE={WRQ:"WRQ",ACK:"ACK",ERROR:"ERROR",CANCEL:"CANCEL",MESSAGE:"MESSAGE"},Skylink.prototype.sendBlobData=function(data,timeout,targetPeerId,sendChunksAsBinary,callback){this._startDataTransfer(data,timeout,targetPeerId,sendChunksAsBinary,callback,"blob")},Skylink.prototype.sendURLData=function(data,timeout,targetPeerId,callback){this._startDataTransfer(data,timeout,targetPeerId,callback,null,"data")},Skylink.prototype.respondBlobRequest=Skylink.prototype.acceptDataTransfer=function(peerId,transferId,accept){var self=this;if("string"!=typeof transferId&&"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as data transfer ID or peer ID is not provided"]);if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as Peer does not have any Datachannel connections"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as invalid transfer ID is provided"]);var channelProp="main";if(self._dataChannels[peerId][transferId]&&(channelProp=transferId),accept){log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]);var dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){console.info(evtPeerId,error,cN,cT),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD,message:new Error("Data transfer terminated as Peer Datachannel connection closed abruptly.")})};self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_STATE.MESSAGING:channelName===transferId)&&[self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED,self.DATA_CHANNEL_STATE.ERROR].indexOf(state)>-1:void self.off("dataChannelState",dataChannelStateCbFn)}),self.once("dataTransferState",function(){dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),delete self._dataTransfers[transferId],self._dataChannels[peerId]&&("main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),channelProp===transferId&&self._closeDataChannel(peerId,transferId))},function(state,evtTransferId,evtPeerId){return evtTransferId===transferId&&evtPeerId===peerId&&[self.DATA_TRANSFER_STATE.ERROR,self.DATA_TRANSFER_STATE.CANCEL,self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED].indexOf(state)>-1}),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:0},channelProp),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_STARTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)}else log.warn([peerId,"RTCDataChannel",transferId,"Rejected data transfer and data transfer request has been aborted"]),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:-1},channelProp),"main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.USER_REJECTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as User has rejected data transfer request."),transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD}),delete self._dataTransfers[transferId]},Skylink.prototype.cancelBlobTransfer=Skylink.prototype.cancelDataTransfer=function(peerId,transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer ID is not provided"]);if(!peerId||"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as peer ID is not provided"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer session does not exists."]);log.debug([peerId,"RTCDataChannel",transferId,"Canceling data transfer ..."]);var emitEventFn=function(peers,transferInfoPeerId){for(var i=0;i0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},"main"),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},transferId),emitEventFn(Object.keys(self._dataTransfers[transferId].peers.main).concat(Object.keys(self._dataTransfers[transferId].peers[transferId])))}else{var channelProp="main";if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as Peer does not have any Datachannel connections"]);self._dataChannels[peerId][transferId]&&(channelProp=transferId),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},channelProp),emitEventFn([peerId],peerId)}},Skylink.prototype.sendP2PMessage=function(message,targetPeerId){var listOfPeers=Object.keys(this._dataChannels),isPrivate=!1;if(Array.isArray(targetPeerId)?(listOfPeers=targetPeerId,isPrivate=!0):targetPeerId&&"string"==typeof targetPeerId&&(listOfPeers=[targetPeerId],isPrivate=!0),!this._inRoom||!this._user||!this._user.sid)return void log.error("Unable to send message as User is not in Room. ->",message);if(!this._enableDataChannel)return void log.error("Unable to send message as User does not have Datachannel enabled. ->",message);for(var i=0;i-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeStreamingFn=function(error){log.error(error)};if(!this._inRoom||!this._user||!this._user.sid)return emitErrorBeforeStreamingFn("Unable to start data streaming as User is not in Room.");if(!this._enableDataChannel)return emitErrorBeforeStreamingFn("Unable to start data streaming as User does not have Datachannel enabled.");if(0===listOfPeers.length)return emitErrorBeforeStreamingFn("Unable to start data streaming as there are no Peers to start session with.");if(self._hasMCU)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature is current not supported by MCU yet.");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},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"===window.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE)};if(peersNonInterop.length>0)if(self._hasMCU)waitForChannelOpenFn("MCU",peersNonInterop);else for(var pni=0;pni0)if(self._hasMCU)startDataSessionFn("MCU","main",peersInterop);else for(var pi=0;piself._CHUNK_DATAURL_SIZE:updatedDataChunk.length>self._BINARY_FILE_SIZE)return void log.error("Failed streaming data chunk as data chunk exceeds maximum chunk limit.");var sessionInfo={chunk:updatedDataChunk,chunkSize:updatedDataChunk.size||updatedDataChunk.length||updatedDataChunk.byteLength,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){var onSendDataFn=function(buffer){self._sendMessageToDataChannel(peerId,buffer,channelProp,!0);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i-1&&"string"!=typeof dataChunk?new Int8Array(dataChunk):dataChunk:new Blob([dataChunk]))};for(var peerId in self._dataStreams[transferId].sessions)if(self._dataStreams[transferId].sessions.hasOwnProperty(peerId)&&self._dataStreams[transferId].sessions[peerId]){var channelProp=self._dataStreams[transferId].sessions[peerId];if(!self._dataChannels[self._hasMCU?"MCU":peerId]||!self._dataChannels[self._hasMCU?"MCU":peerId][channelProp]||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].channel.readyState!==self.DATA_CHANNEL_STATE.OPEN||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].streamId!==transferId)return log.error([peerId,"RTCDataChannel",transferId,"Failed streaming data as it has not started or is ready."]),void self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,peerId,sessionInfo,new Error("Streaming as it has not started or Datachannel connection is not open."));self._hasMCU?"main"===channelProp?peersInterop.push(peerId):peersNonInterop.push(peerId):sendDataFn(peerId,channelProp)}self._hasMCU&&(peersInterop.length>0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype.stopStreamingData=function(transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error("Failed streaming data chunk as stream session ID is not provided.");if(!(self._inRoom&&self._user&&self._user.sid))return void log.error("Failed streaming data chunk as User is not in the Room.");if(!self._dataStreams[transferId])return void log.error("Failed stopping data streaming session as it does not exists.");if(!self._dataStreams[transferId].isUpload)return void log.error("Failed stopping data streaming session as it is not sending.");if(self._hasMCU)return void log.error("Failed stopping data streaming session as MCU does not support this feature yet.");var sessionInfo={chunk:null,chunkSize:0,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:transferId,size:0,originalSize:0,dataType:"fastBinaryStop",mimeType:null,chunkType:self._dataStreams[transferId].sessionChunkType,chunkSize:0,timeout:0,isPrivate:self._dataStreams[transferId].isPrivate,sender:self._user.sid,agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers||peerId},channelProp);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype._startDataTransfer=function(data,timeout,targetPeerId,sendChunksAsBinary,callback,sessionType){var self=this,transferId=(self._user?self._user.sid:"")+"_"+(new Date).getTime(),transferErrors={},transferCompleted=[],chunks=[],listOfPeers=Object.keys(self._peerConnections),sessionChunkType="string",transferInfo={name:null,size:null,chunkSize:null,chunkType:null,dataType:null,mimeType:null,direction:self.DATA_TRANSFER_TYPE.UPLOAD,timeout:60,isPrivate:!1,percentage:0};"number"==typeof timeout?transferInfo.timeout=timeout:Array.isArray(timeout)?listOfPeers=timeout:timeout&&"string"==typeof timeout?listOfPeers=[timeout]:timeout&&"boolean"==typeof timeout?sessionChunkType="binary":"function"==typeof timeout&&(callback=timeout),Array.isArray(targetPeerId)?listOfPeers=targetPeerId:targetPeerId&&"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:targetPeerId&&"boolean"==typeof targetPeerId?sessionChunkType="binary":"function"==typeof targetPeerId&&(callback=targetPeerId),sendChunksAsBinary&&"boolean"==typeof sendChunksAsBinary?sessionChunkType="binary":"function"==typeof sendChunksAsBinary&&(callback=sendChunksAsBinary),listOfPeers.indexOf("MCU")>-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeDataTransferFn=function(error){if(log.error(error),"function"==typeof callback){var transferErrors={};if(0===listOfPeers.length)transferErrors.self=new Error(error);else for(var i=0;i0){var bsChunkSize="firefox"===window.webrtcDetectedBrowser?self._MOZ_CHUNK_FILE_SIZE:self._CHUNK_FILE_SIZE,bsChunks=self._chunkBlobData(new Blob(chunks),bsChunkSize);self._dataTransfers[transferId].enforceBSInfo={chunkSize:4*Math.ceil(bsChunkSize/3),chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,size:4*Math.ceil(transferInfo.originalSize/3),chunks:bsChunks}}}for(var completeFn=function(peerId,error){transferCompleted.indexOf(peerId)>-1||(log.debug([peerId,"RTCDataChannel",transferId,"Data transfer result. Is errors present? ->"],error),transferCompleted.push(peerId),error&&(transferErrors[peerId]=new Error(error)),listOfPeers.length===transferCompleted.length&&(log.log([null,"RTCDataChannel",transferId,"Data transfer request completed"]),"function"==typeof callback&&(Object.keys(transferErrors).length>0?callback({transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),transferErrors:transferErrors,listOfPeers:listOfPeers},null):callback(null,{transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),listOfPeers:listOfPeers}))))},i=0;i0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,"main",Object.keys(self._dataTransfers[transferId].peers.main)),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,transferId,Object.keys(self._dataTransfers[transferId].peers[transferId])))},Skylink.prototype._startDataTransferToPeer=function(transferId,peerId,callback,channelProp,targetPeers){var self=this,peerConnectionStateCbFn=null,dataChannelStateCbFn=null,emitEventFn=function(cb){for(var peers=targetPeers||[peerId],i=0;i-1&&(log.warn([peerId,"RTCDataChannel",transferId,"Binary data chunks transfer is not yet supported with Peer connecting from Android, iOS and C++ SDK. Fallbacking to binary string data chunks transfer."]),size=self._dataTransfers[transferId].enforceBSInfo.size,chunkSize=self._dataTransfers[transferId].enforceBSInfo.chunkSize,chunkType="string"),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:self._dataTransfers[transferId].name,size:size,originalSize:self._dataTransfers[transferId].originalSize,dataType:self._dataTransfers[transferId].sessionType,mimeType:self._dataTransfers[transferId].mimeType,chunkType:chunkType,chunkSize:chunkSize,timeout:self._dataTransfers[transferId].timeout,isPrivate:self._dataTransfers[transferId].isPrivate,sender:self._user.sid,agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers||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");return self._isLowerThanVersion(protocolVer,"0.1.2")&&"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer do not support DATA_URL type of data transfers"):"MCU"!==peerId&&self._hasMCU?(channelProp=requireInterop?"main":transferId,peerConnectionStateCbFn=function(){returnErrorBeforeTransferFn("Data transfer terminated as Peer connection is not stable.")},self.once("peerConnectionState",peerConnectionStateCbFn,function(state,evtPeerId){return self._dataTransfers[transferId]?state!==self.PEER_CONNECTION_STATE.STABLE&&evtPeerId===peerId:void self.off("peerConnectionState",peerConnectionStateCbFn)}),requireInterop):(requireInterop||"main"===channelProp)&&self._dataChannels[peerId].main.transferId?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel has a data transfer in-progress."):(self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0},dataChannelStateCbFn=function(state,evtPeerId,error){self._dataTransfers[transferId].sessions[peerId].ackN>=self._dataTransfers[transferId].chunks.length-1||returnErrorBeforeTransferFn(error?error.message||error.toString():"Data transfer terminated as Peer Datachannel connection closed abruptly.")},self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName===transferId?(self._dataChannels[peerId][channelProp].transferId=transferId,sendWRQFn(),!1):[self.DATA_CHANNEL_STATE.CREATE_ERROR,self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1:void self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(self._dataChannels[peerId].main.transferId=transferId,sendWRQFn()):(channelProp=transferId,self._createDataChannel(peerId,transferId,"data"===self._dataTransfers[transferId].sessionType?self._CHUNK_DATAURL_SIZE:"string"===self._dataTransfers[transferId].sessionChunkType?"firefox"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE))))},Skylink.prototype._getTransferInfo=function(transferId,peerId,returnDataProp,hidePercentage,returnDataAtStart){if(!this._dataTransfers[transferId])return{};var transferInfo={name:this._dataTransfers[transferId].name,size:this._dataTransfers[transferId].size,dataType:this._dataTransfers[transferId].dataType||this.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:this._dataTransfers[transferId].mimeType||null,chunkSize:this._dataTransfers[transferId].chunkSize,chunkType:this._dataTransfers[transferId].chunkType,timeout:this._dataTransfers[transferId].timeout,isPrivate:this._dataTransfers[transferId].isPrivate,direction:this._dataTransfers[transferId].direction};if(this._dataTransfers[transferId].originalSize?transferInfo.size=this._dataTransfers[transferId].originalSize:this._dataTransfers[transferId].chunkType===this.DATA_TRANSFER_DATA_TYPE.BINARY_STRING&&(transferInfo.size=Math.ceil(3*transferInfo.size/4)),!hidePercentage){if(transferInfo.percentage=0,!this._dataTransfers[transferId].sessions[peerId])return returnDataProp&&(transferInfo.data=null),transferInfo;if(this._dataTransfers[transferId].direction===this.DATA_TRANSFER_TYPE.DOWNLOAD)this._dataTransfers[transferId].sessions[peerId].receivedSize===this._dataTransfers[transferId].sessions[peerId].size?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].receivedSize/this._dataTransfers[transferId].size*100).toFixed(2),10);else{var chunksLength=this._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?this._dataTransfers[transferId].enforceBSInfo.chunks.length:this._dataTransfers[transferId].chunks.length;this._dataTransfers[transferId].sessions[peerId].ackN===chunksLength?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].ackN/chunksLength*100).toFixed(2),10)}returnDataProp&&("number"!=typeof returnDataAtStart?100===transferInfo.percentage?transferInfo.data=this._getTransferData(transferId):transferInfo.data=null:(transferInfo.percentage=returnDataAtStart,0===returnDataAtStart&&(transferInfo.data=this._getTransferData(transferId))))}return transferInfo},Skylink.prototype._getTransferData=function(transferId){if(!this._dataTransfers[transferId])return null;if(this._dataTransfers[transferId].dataType===this.DATA_TRANSFER_SESSION_TYPE.BLOB){var mimeType={name:this._dataTransfers[transferId].name};return this._dataTransfers[transferId].mimeType&&(mimeType.type=this._dataTransfers[transferId].mimeType),new Blob(this._dataTransfers[transferId].chunks,mimeType)}return this._dataTransfers[transferId].chunks.join("")},Skylink.prototype._handleDataTransferTimeoutForPeer=function(transferId,peerId,setPeerTO){var self=this;if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer does not exists for Peer. Ignoring timeout."]);log.debug([peerId,"RTCDataChannel",transferId,"Clearing data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer&&clearTimeout(self._dataTransfers[transferId].sessions[peerId].timer),self._dataTransfers[transferId].sessions[peerId].timer=null,setPeerTO&&(log.debug([peerId,"RTCDataChannel",transferId,"Setting data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer=setTimeout(function(){if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer already ended for Peer. Ignoring expired timeout."]);if(!self._user||!self._user.sid)return void log.debug([peerId,"RTCDataChannel",transferId,"User is not in Room. Ignoring expired timeout."]);if(!self._dataChannels[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Datachannel connection does not exists. Ignoring expired timeout."]);log.error([peerId,"RTCDataChannel",transferId,"Data transfer response has timed out."]);var 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"===window.webrtcDetectedBrowser){if(window.BlobBuilder){var bb=new BlobBuilder;bb.append(rawData.constructor&&"ArrayBuffer"===rawData.constructor.name?byteArray:new Uint8Array(byteArray).buffer),blob=bb.getBlob()}}else blob=new Blob([byteArray]);log.debug([peerId,"RTCDataChannel",channelProp,"Received arraybuffer data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],blob.size),self._DATAProtocolHandler(peerId,blob,self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,blob.size,channelProp)}}},Skylink.prototype._WRQProtocolHandler=function(peerId,data,channelProp){var self=this,transferId="main"===channelProp?data.transferId||null:channelProp,senderPeerId=data.sender||peerId;if(["fastBinaryStart","fastBinaryStop"].indexOf(data.dataType)>-1)if("fastBinaryStart"===data.dataType){transferId||(transferId="stream_"+peerId+"_"+(new Date).getTime()),self._dataStreams[transferId]={chunkSize:0,chunkType:"string"===data.chunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:data.chunkType,isPrivate:!!data.isPrivate,isStringStream:"string"===data.chunkType,senderPeerId:senderPeerId,isUpload:!1},self._dataChannels[peerId][channelProp].streamId=transferId;self.once("dataChannelState",function(){},function(state,evtPeerId,channelName,channelType,error){if(!self._dataStreams[transferId])return!0;if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId&&channelType===self.DATA_CHANNEL_TYPE.DATA)&&[self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');return self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},updatedError),!0}}),self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STARTED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStarted",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1)}else transferId=self._dataChannels[peerId][channelProp].streamId,self._dataStreams[transferId]&&!self._dataStreams[transferId].isUpload&&(self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STOPPED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStopped",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1),self._dataChannels[peerId][channelProp].streamId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp),delete self._dataStreams[transferId]);else transferId||(transferId="transfer_"+peerId+"_"+(new Date).getTime()),self._dataTransfers[transferId]={name:data.name||transferId,size:data.size||0,chunkSize:data.chunkSize,originalSize:data.originalSize||0,timeout:data.timeout||60,isPrivate:!!data.isPrivate,senderPeerId:data.sender||peerId,dataType:self.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:data.mimeType||null,chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,direction:self.DATA_TRANSFER_TYPE.DOWNLOAD,chunks:[],sessions:{},sessionType:data.dataType||"blob",sessionChunkType:data.chunkType||"string"},"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?(self._dataTransfers[transferId].dataType=self.DATA_TRANSFER_SESSION_TYPE.DATA_URL,self._dataTransfers[transferId].chunkType=self.DATA_TRANSFER_DATA_TYPE.STRING):"blob"===self._dataTransfers[transferId].sessionType&&"binary"===self._dataTransfers[transferId].sessionChunkType&&(self._dataTransfers[transferId].chunkType=self._binaryChunkType),self._dataChannels[peerId][channelProp].transferId=transferId,self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0,receivedSize:0},self._trigger("incomingDataRequest",transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!1),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_REQUEST,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)},Skylink.prototype._ACKProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ACK event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};if(data.ackN>-1){if(0===data.ackN)emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_STARTED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,0),null)});else if(self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?data.ackN===self._dataTransfers[transferId].enforceBSInfo.chunks.length:data.ackN===self._dataTransfers[transferId].chunks.length)return self._dataTransfers[transferId].sessions[peerId].ackN=data.ackN,emitEventFn(function(evtPeerId){self._trigger("incomingData",self._getTransferData(transferId),transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,100),null)}),void(self._dataChannels[peerId][channelProp]&&(self._dataChannels[peerId][channelProp].transferId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp)));var uploadFn=function(chunk){self._sendMessageToDataChannel(peerId,chunk,channelProp,!0),data.ackN-1?self._blobToBase64(self._dataTransfers[transferId].enforceBSInfo.chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING?self._blobToBase64(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER?self._blobToArrayBuffer(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):uploadFn(self._dataTransfers[transferId].chunks[data.ackN])}else self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.REJECTED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as Peer has rejected data transfer request"),transferType:self.DATA_TRANSFER_TYPE.UPLOAD})},Skylink.prototype._MESSAGEProtocolHandler=function(peerId,data,channelProp){var senderPeerId=data.sender||peerId;log.log([senderPeerId,"RTCDataChannel",channelProp,"Received P2P message from peer:"],data),this._trigger("incomingMessage",{content:data.data,isPrivate:data.isPrivate,isDataChannel:!0,targetPeerId:this._user.sid,senderPeerId:senderPeerId},senderPeerId,this.getPeerInfo(senderPeerId),!1)},Skylink.prototype._ERRORProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,userInfo:self._getUserInfo(targetMid),target:targetMid,rid:self._room.id})}}},Skylink.prototype._addIceCandidateToQueue=function(targetMid,canId,candidate){var candidateType=candidate.candidate.split(" ")[7];log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Buffering ICE candidate."]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.BUFFERED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[],this._peerCandidatesQueue[targetMid].push([canId,candidate])},Skylink.prototype._addIceCandidateFromQueue=function(targetMid){this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[];for(var i=0;i"],error),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESS_ERROR,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},error)};if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Adding ICE candidate."]),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESSING,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[targetMid].remoteDescription&&self._peerConnections[targetMid].remoteDescription.sdp&&self._peerConnections[targetMid].remoteDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),void self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),-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"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}},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"===window.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;if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]),"edge"===window.webrtcDetectedBrowser)return callback(new Error("Edge does not support stats"));if(!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},Skylink.prototype._addPeer=function(targetMid,cert,peerBrowser,receiveOnly,isSS){var self=this;return self._peerConnections[targetMid]?void log.error([targetMid,null,null,"Connection to peer has already been made"]):(self._peerConnStatus[targetMid]={connected:!1,init:!1},log.log([targetMid,null,null,"Starting the connection to peer. Options provided:"],{peerBrowser:peerBrowser,receiveOnly:receiveOnly,enableDataChannel:self._enableDataChannel}),log.info("Adding peer",isSS),self._peerConnections[targetMid]=self._createPeerConnection(targetMid,!!isSS,cert),self._peerConnections[targetMid]?(self._peerConnStatus[targetMid].init=!0,void(self._peerConnections[targetMid].hasScreen=!!isSS)):void log.error([targetMid,null,null,"Failed creating the connection to peer."]))},Skylink.prototype._restartPeerConnection=function(peerId,doIceRestart,bwOptions,callback){var self=this;if(!self._peerConnections[peerId])return void log.error([peerId,null,null,"Peer does not have an existing connection. Unable to restart"]);var pc=self._peerConnections[peerId],agent=(self.getPeerInfo(peerId)||{}).agent||{};if(self._isLowerThanVersion(agent.SMProtocolVersion||"","0.1.2")){var notSupportedError=new Error("Failed restarting with other agents connecting from other SDKs as re-negotiation is not supported by other SDKs");return log.warn([peerId,"RTCPeerConnection",null,"Ignoring restart request as agent's SDK does not support it"],notSupportedError),void("function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(notSupportedError)))}if(pc.signalingState===self.PEER_CONNECTION_STATE.STABLE&&self._peerConnections[peerId]){log.log([peerId,null,null,"Sending restart message to signaling server ->"],{iceRestart:doIceRestart,options:bwOptions}),self._peerCustomConfigs[peerId]=self._peerCustomConfigs[peerId]||{},self._peerCustomConfigs[peerId].bandwidth=self._peerCustomConfigs[peerId].bandwidth||{},self._peerCustomConfigs[peerId].googleXBandwidth=self._peerCustomConfigs[peerId].googleXBandwidth||{},bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._peerCustomConfigs[peerId].bandwidth.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._peerCustomConfigs[peerId].bandwidth.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._peerCustomConfigs[peerId].bandwidth.data=bwOptions.bandwidth.data)), bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._peerCustomConfigs[peerId].googleXBandwidth.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._peerCustomConfigs[peerId].googleXBandwidth.max=bwOptions.googleXBandwidth.max));var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!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(),"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,self._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}},self._streamsSession[targetMid]=self._streamsSession[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._sdpSessions[targetMid]={local:{},remote:{}},self._peerBandwidth[targetMid]={};var bandwidth=null;return pc.ondatachannel=function(event){var dc=event.channel||event;if(log.debug([targetMid,"RTCDataChannel",dc.label,"Received datachannel ->"],dc),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel){self.DATA_CHANNEL_TYPE.DATA,dc.label;pc.hasMainChannel||(self.DATA_CHANNEL_TYPE.MESSAGING,"main",pc.hasMainChannel=!0),self._createDataChannel(targetMid,dc)}else log.warn([targetMid,"RTCDataChannel",dc.label,"Not adding datachannel as enable datachannel is set to false"])},pc.onaddstream=function(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&-1===pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" "))return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},pc.onicecandidate=function(event){self._onIceCandidate(targetMid,event.candidate||event)},pc.oniceconnectionstatechange=function(evt){var iceConnectionState=pc.iceConnectionState;if(log.debug([targetMid,"RTCIceConnectionState",null,"Ice connection state changed ->"],iceConnectionState),"edge"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._enableIceTrickle&&self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.TRICKLE_FAILED,targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].connected=[self.ICE_CONNECTION_STATE.COMPLETED,self.ICE_CONNECTION_STATE.CONNECTED].indexOf(iceConnectionState)>-1),!self._hasMCU&&[self.ICE_CONNECTION_STATE.CONNECTED,self.ICE_CONNECTION_STATE.COMPLETED].indexOf(iceConnectionState)>-1&&self._bandwidthAdjuster&&!bandwidth&&"edge"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),self._trigger("peerConnectionState",pc.signalingState,targetMid)},pc.onicegatheringstatechange=function(){log.log([targetMid,"RTCIceGatheringState",null,"Ice gathering state changed ->"],pc.iceGatheringState),self._trigger("candidateGenerationState",pc.iceGatheringState,targetMid)},"firefox"===window.webrtcDetectedBrowser&&(pc.removeStream=function(stream){for(var senders=pc.getSenders(),s=0;s"],restartMsg),self._sendChannelMessage(restartMsg)};bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=bwOptions.googleXBandwidth.max));for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers},null):callback(null,{listOfPeers:listOfPeers}))};self.once("peerJoined",peerJoinedFn,function(peerId,peerInfo,isSelf){return isSelf}),self.leaveRoom(!1,function(error,success){if(error){if("function"==typeof callback){for(var i=0;i=self._peerEndOfCandidatesCounter[targetMid].expectedLen&&(!self._peerCandidatesQueue[targetMid]||0===self._peerCandidatesQueue[targetMid].length)&&!self._peerEndOfCandidatesCounter[targetMid].hasSet){log.debug([targetMid,"RTCPeerConnection",null,"Signaling of end-of-candidates remote ICE gathering."]),self._peerEndOfCandidatesCounter[targetMid].hasSet=!0;try{if("edge"===window.webrtcDetectedBrowser){for(var mLineCounter=-1,addedMids=[],sdpLines=self._peerConnections[targetMid].remoteDescription.sdp.split("\r\n"),rejected=!1,i=0;i"],error)}}},Skylink.prototype.setUserData=function(userData){var self=this,updatedUserData="";void 0!==userData&&null!==userData&&(updatedUserData=userData),this._userData=updatedUserData,self._inRoom?(log.log("Updated userData -> ",updatedUserData),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.UPDATE_USER,mid:self._user.sid,rid:self._room.id,userData:updatedUserData,stamp:(new Date).getTime()}),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0)):log.warn("User is not in the room. Broadcast of updated information will be dropped")},Skylink.prototype.getUserData=function(peerId){if(peerId&&this._peerInformations[peerId]){var userData=this._peerInformations[peerId].userData;return null!==userData&&void 0===userData||(userData=""),userData}return this._userData},Skylink.prototype.getPeerInfo=function(peerId){var peerInfo=null;return"string"==typeof peerId&&"object"==typeof this._peerInformations[peerId]?(peerInfo=clone(this._peerInformations[peerId]),peerInfo.room=clone(this._selectedRoom),peerInfo.settings.bandwidth=peerInfo.settings.bandwidth||{},peerInfo.settings.googleXBandwidth=peerInfo.settings.googleXBandwidth||{},"boolean"==typeof peerInfo.settings.video||peerInfo.settings.video&&"object"==typeof peerInfo.settings.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"==typeof peerInfo.settings.audio||peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.audioMuted&&(peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.videoMuted&&(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.maxBandwidth&&(peerInfo.settings.bandwidth=clone(peerInfo.settings.maxBandwidth),delete peerInfo.settings.maxBandwidth),peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&peerInfo.settings.video.customSettings&&"object"==typeof peerInfo.settings.video.customSettings&&(peerInfo.settings.video.customSettings.frameRate&&(peerInfo.settings.video.frameRate=clone(peerInfo.settings.video.customSettings.frameRate)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode)),peerInfo.settings.video.customSettings.width&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.width=clone(peerInfo.settings.video.customSettings.width)),peerInfo.settings.video.customSettings.height&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.height=clone(peerInfo.settings.video.customSettings.height)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode))),peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&(peerInfo.settings.audio.stereo=!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)),this._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0)):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,os:window.navigator.platform,pluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:this.SMProtocolVersion,DTProtocolVersion:this.DTProtocolVersion},room:clone(this._selectedRoom),config:{enableDataChannel:this._enableDataChannel,enableIceTrickle:this._enableIceTrickle,enableIceRestart:this._enableIceRestart,priorityWeight:this._peerPriorityWeight,receiveOnly:!1,publishOnly:!!this._publishOnly},connected:null,init:null},null!==peerInfo.userData&&void 0!==peerInfo.userData||(peerInfo.userData=""),this._streams.screenshare?peerInfo.settings=clone(this._streams.screenshare.settings):this._streams.userMedia&&(peerInfo.settings=clone(this._streams.userMedia.settings)),peerInfo.settings.bandwidth=clone(this._streamsBandwidthSettings.bAS),peerInfo.settings.googleXBandwidth=clone(this._streamsBandwidthSettings.googleX),peerInfo.parentId=this._parentId?this._parentId:null,peerInfo.config.receiveOnly=!peerInfo.settings.video&&!peerInfo.settings.audio,peerInfo.settings.data=this._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._codecParams.audio.opus.useinbandfec))),peerInfo.settings.audio||(peerInfo.mediaStatus.audioMuted=!0),peerInfo.settings.video||(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.audio||peerInfo.settings.video||(peerInfo.config.receiveOnly=!0,peerInfo.config.publishOnly=!1),peerInfo},Skylink.prototype.getPeersInRoom=function(){for(var listOfPeersInfo={},listOfPeers=Object.keys(this._peerInformations),i=0;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i-1||(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.settings.video&&!self._getSDPEdgeVideoSupports(usePeerId)&&(customSettings.settings.video=!1,customSettings.mediaStatus.videoMuted=!0),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),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype.HANDSHAKE_PROGRESS={ENTER:"enter",WELCOME:"welcome",OFFER:"offer",ANSWER:"answer",ERROR:"error"},Skylink.prototype._doOffer=function(targetMid,iceRestart,peerBrowser){var self=this,pc=self._peerConnections[targetMid];if(log.log([targetMid,null,null,"Checking caller status"],peerBrowser),!pc)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of creating of offer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription","offer",'Dropping of creating of offer as signalingState is not "'+self.PEER_CONNECTION_STATE.STABLE+'" ->'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._dataChannels[targetMid]&&self._dataChannels[targetMid].main||(self._createDataChannel(targetMid),self._peerConnections[targetMid].hasMainChannel=!0)),log.debug([targetMid,null,null,"Creating offer with config:"],offerConstraints),pc.endOfCandidates=!1,self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=offerConstraints),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},offerConstraints)},Skylink.prototype._doAnswer=function(targetMid){var self=this;log.log([targetMid,null,null,"Creating answer with config:"],self._room.connection.sdpConstraints);var pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of creating of answer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription","answer",'Dropping of creating of answer as signalingState is not "'+self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER+'" ->'],pc.signalingState);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,_sessionDescription){var self=this,pc=self._peerConnections[targetMid];if(!_sessionDescription||!_sessionDescription.sdp)return void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],_sessionDescription);if(!pc)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as connection does not exists ->"],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(pc.processingLocalSDP)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as another is being processed ->"],_sessionDescription);pc.processingLocalSDP=!0;var sessionDescription={type:_sessionDescription.type,sdp:_sessionDescription.sdp};sessionDescription.sdp=self._removeSDPFirefoxH264Pref(targetMid,sessionDescription),sessionDescription.sdp=self._setSDPCodecParams(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPUnknownAptRtx(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPCodecs(targetMid,sessionDescription),sessionDescription.sdp=self._handleSDPConnectionSettings(targetMid,sessionDescription,"local"),sessionDescription.sdp=self._removeSDPREMBPackets(targetMid,sessionDescription),log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description updated ->"],sessionDescription.sdp),pc.setLocalDescription(new RTCSessionDescription(sessionDescription),function(){if(log.debug([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description has been set ->"],sessionDescription),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",sessionDescription.type,targetMid),sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER?pc.setAnswer="local":pc.setOffer="local",!self._enableIceTrickle&&!pc.gathered)return void log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description sending is halted to complete ICE gathering."]);self._sendChannelMessage({type:sessionDescription.type,sdp:self._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},function(error){log.error([targetMid,"RTCSessionDescription",sessionDescription.type,"Local description failed setting ->"],error),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)})},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._appKey?("function"==typeof showAll&&(callback=showAll,showAll=!1),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.GET_PEERS,showAll:showAll||!1}),self._trigger("getPeersStateChange",self.GET_PEERS_STATE.ENQUIRED,self._user.sid,null),log.log("Enquired server for peers within the realm"),void("function"==typeof callback&&self.once("getPeersStateChange",function(state,privilegedPeerId,peerList){callback(null,peerList)},function(state,privilegedPeerId,peerList){return state===self.GET_PEERS_STATE.RECEIVED}))):void log.warn("App key is not defined. Please authenticate again."):void log.warn("Please upgrade your key to privileged to use this function")},Skylink.prototype.introducePeer=function(sendingPeerId,receivingPeerId){var self=this;if(!self._isPrivileged)return log.warn("Please upgrade your key to privileged to use this function"),void self._trigger("introduceStateChange",self.INTRODUCE_STATE.ERROR,self._user.sid,sendingPeerId,receivingPeerId,"notPrivileged");self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.INTRODUCE,sendingPeerId:sendingPeerId,receivingPeerId:receivingPeerId}),self._trigger("introduceStateChange",self.INTRODUCE_STATE.INTRODUCING,self._user.sid,sendingPeerId,receivingPeerId,null),log.log("Introducing",sendingPeerId,"to",receivingPeerId)},Skylink.prototype.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};room&&"string"==typeof room?selectedRoom=room:room&&"object"==typeof room?mediaOptions=room:"function"==typeof room&&(callback=room),options&&"object"==typeof options?mediaOptions=options:"function"==typeof options&&(callback=options);var resolveAsErrorFn=function(error,tryRoom,readyState){log.error(error),"function"==typeof callback&&callback({room:tryRoom,errorCode:readyState||null,error: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("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.23",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;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,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break} -options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,maxplaybackrate:"number"==typeof options.codecParams.audio.opus.maxplaybackrate&&options.codecParams.audio.opus.maxplaybackrate>=8e3&&options.codecParams.audio.opus.maxplaybackrate<=48e3?options.codecParams.audio.opus.maxplaybackrate:null,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),!0===forceTURN&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,self._useEdgeWebRTC=useEdgeWebRTC,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}),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})):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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"Network error occurred. (Status: "+xhr.status+")",errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom)},xhr.onprogress=function(){log.debug([null,"XMLHttpRequest",method,"Retrieving information and config from webserver. Url:"],url),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},Skylink.prototype._parseInfo=function(info){if(log.log("Parsing parameter from server",info),!info.pc_constraints&&!info.offer_constraints)return void this._trigger("readyStateChange",this.READY_STATE_CHANGE.ERROR,{status:200,content:info.info,errorCode:info.error},self._selectedRoom);log.debug("Peer connection constraints:",info.pc_constraints),log.debug("Offer constraints:",info.offer_constraints),this._key=info.cid,this._appKeyOwner=info.apiOwner,this._signalingServer=info.ipSigserver,this._isPrivileged=info.isPrivileged,this._autoIntroduce=info.autoIntroduce,this._user={uid:info.username,token:info.userCred,timeStamp:info.timeStamp,streams:[],info:{}},this._room={id:info.room_key,token:info.roomCred,startDateTime:info.start,duration:info.len,connection:{peerConstraints:JSON.parse(info.pc_constraints),peerConfig:null,offerConstraints:JSON.parse(info.offer_constraints),sdpConstraints:{mandatory:{OfferToReceiveAudio:!0,OfferToReceiveVideo:!0}},mediaConstraints:JSON.parse(info.media_constraints)}},this._socketPorts={"http:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,this._trigger("readyStateChange",this.READY_STATE_CHANGE.COMPLETED,null,this._selectedRoom),log.info("Parsed parameters from webserver. Ready for web-realtime communication")},Skylink.prototype._loadInfo=function(){var self=this,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!function(){try{var p=new window.RTCPeerConnection(null);return["object","function"].indexOf(typeof p.createOffer)>-1&&null!==p.createOffer}catch(e){return!1}}())return window.RTCPeerConnection&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);self._getCodecsSupport(function(error){return error?(log.error(error),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:error.message||error.toString(),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):0===Object.keys(self._currentCodecSupport.audio).length&&0===Object.keys(self._currentCodecSupport.video).length?(log.error("No audio/video codecs available to start connection."),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No API Path is found",errorCode:self.READY_STATE_CHANGE_ERROR.NO_PATH},self._selectedRoom)):(log.error("XMLHttpRequest not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"XMLHttpRequest not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_XMLHTTPREQUEST_SUPPORT},self._selectedRoom)):(log.error("Socket.io not loaded. Please load socket.io"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"Socket.io not found",errorCode:self.READY_STATE_CHANGE_ERROR.NO_SOCKET_IO},self._selectedRoom))},Skylink.prototype._initSelectedRoom=function(room,callback){var self=this;if("function"==typeof room||void 0===room)return void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null,useEdgeWebRTC:self._useEdgeWebRTC};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)), +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"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,self._useEdgeWebRTC=useEdgeWebRTC,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}),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})):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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"Network error occurred. (Status: "+xhr.status+")",errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom)},xhr.onprogress=function(){log.debug([null,"XMLHttpRequest",method,"Retrieving information and config from webserver. Url:"],url),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},Skylink.prototype._parseInfo=function(info){if(log.log("Parsing parameter from server",info),!info.pc_constraints&&!info.offer_constraints)return void this._trigger("readyStateChange",this.READY_STATE_CHANGE.ERROR,{status:200,content:info.info,errorCode:info.error},self._selectedRoom);log.debug("Peer connection constraints:",info.pc_constraints),log.debug("Offer constraints:",info.offer_constraints),this._key=info.cid,this._appKeyOwner=info.apiOwner,this._signalingServer=info.ipSigserver,this._isPrivileged=info.isPrivileged,this._autoIntroduce=info.autoIntroduce,this._user={uid:info.username,token:info.userCred,timeStamp:info.timeStamp,streams:[],info:{}},this._room={id:info.room_key,token:info.roomCred,startDateTime:info.start,duration:info.len,connection:{peerConstraints:JSON.parse(info.pc_constraints),peerConfig:null,offerConstraints:JSON.parse(info.offer_constraints),sdpConstraints:{mandatory:{OfferToReceiveAudio:!0,OfferToReceiveVideo:!0}},mediaConstraints:JSON.parse(info.media_constraints)}},this._socketPorts={"http:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,this._trigger("readyStateChange",this.READY_STATE_CHANGE.COMPLETED,null,this._selectedRoom),log.info("Parsed parameters from webserver. Ready for web-realtime communication")},Skylink.prototype._loadInfo=function(){var self=this,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!function(){try{var p=new window.RTCPeerConnection(null);return["object","function"].indexOf(typeof p.createOffer)>-1&&null!==p.createOffer}catch(e){return!1}}())return window.RTCPeerConnection&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);self._getCodecsSupport(function(error){return error?(log.error(error),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:error.message||error.toString(),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):0===Object.keys(self._currentCodecSupport.audio).length&&0===Object.keys(self._currentCodecSupport.video).length?(log.error("No audio/video codecs available to start connection."),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No API Path is found",errorCode:self.READY_STATE_CHANGE_ERROR.NO_PATH},self._selectedRoom)):(log.error("XMLHttpRequest not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"XMLHttpRequest not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_XMLHTTPREQUEST_SUPPORT},self._selectedRoom)):(log.error("Socket.io not loaded. Please load socket.io"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"Socket.io not found",errorCode:self.READY_STATE_CHANGE_ERROR.NO_SOCKET_IO},self._selectedRoom))},Skylink.prototype._initSelectedRoom=function(room,callback){var self=this;if("function"==typeof room||void 0===room)return void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null,useEdgeWebRTC:self._useEdgeWebRTC};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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,target:message.target,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._redirectHandler=function(message){if(log.log(["Server",null,message.type,"System action warning:"],{message:message.info,reason:message.reason,action:message.action}),message.action===this.SYSTEM_ACTION.REJECT)for(var key in this._peerConnections)this._peerConnections.hasOwnProperty(key)&&this._removePeer(key);"toClose"===message.reason&&(message.reason="toclose"),this._trigger("systemAction",message.action,message.info,message.reason)},Skylink.prototype._updateUserEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer updated userData:"],message.userData),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].userData=message.stamp}this._peerInformations[targetMid].userData=message.userData||{},this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._roomLockEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,message.type,"Room lock status:"],message.lock),this._trigger("roomLock",message.lock,targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._muteAudioEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's audio muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].audioMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.audioMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,message.type,"Peer does not have any user information"])},Skylink.prototype._muteVideoEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's video muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].videoMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.videoMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._streamEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Peer's stream status:"],message.status),this._peerInformations[targetMid]&&message.streamId?(this._streamsSession[targetMid]=this._streamsSession[targetMid]||{},"ended"===message.status&&(message.settings&&"object"==typeof message.settings&&void 0===this._streamsSession[targetMid][message.streamId]&&(this._streamsSession[targetMid][message.streamId]={audio:message.settings.audio,video:message.settings.video}),this._handleEndedStreams(targetMid,message.streamId))):log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._byeHandler=function(message){var targetMid=message.mid;(this._user||{}).sid!==targetMid?(log.log([targetMid,null,message.type,"Peer has left the room"]),this._removePeer(targetMid)):log.log([targetMid,null,message.type,"Self has left the room"])},Skylink.prototype._privateMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received private message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!0,targetPeerId:message.target,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._publicMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received public message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!1,targetPeerId:null,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._recordingEventHandler=function(message){var self=this;if(log.debug(["MCU","Recording",null,"Received recording message ->"],message),"on"===message.action)self._recordings[message.recordingId]||(log.debug(["MCU","Recording",message.recordingId,"Started recording"]),self._currentRecordingId=message.recordingId,self._recordings[message.recordingId]={active:!0,state:self.RECORDING_STATE.START,startedDateTime:(new Date).toISOString(),endedDateTime:null,mixingDateTime:null,links:null,error:null},self._recordingStartInterval=setTimeout(function(){log.log(["MCU","Recording",message.recordingId,"4 seconds has been recorded. Recording can be stopped now"]),self._recordingStartInterval=null},4e3),self._trigger("recordingState",self.RECORDING_STATE.START,message.recordingId,null,null));else if("off"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,'Received request of "off" but the session is empty']);self._currentRecordingId=null,self._recordingStartInterval&&(clearTimeout(self._recordingStartInterval),log.warn(["MCU","Recording",message.recordingId,"Recording stopped abruptly before 4 seconds"]),self._recordingStartInterval=null),log.debug(["MCU","Recording",message.recordingId,"Stopped recording"]),self._recordings[message.recordingId].active=!1,self._recordings[message.recordingId].state=self.RECORDING_STATE.STOP,self._recordings[message.recordingId].endedDateTime=(new Date).toISOString(),self._trigger("recordingState",self.RECORDING_STATE.STOP,message.recordingId,null,null)}else if("url"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,"Received URL but the session is empty"]);var links={};if(Array.isArray(message.urls))for(var i=0;i"],recordingError);log.error(["MCU","Recording",message.recordingId,"Recording failure ->"],recordingError),self._recordings[message.recordingId].state=self.RECORDING_STATE.ERROR,self._recordings[message.recordingId].error=recordingError,self._recordings[message.recordingId].active&&(log.debug(["MCU","Recording",message.recordingId,"Stopped recording abruptly"]),self._recordings[message.recordingId].active=!1),self._trigger("recordingState",self.RECORDING_STATE.ERROR,message.recordingId,null,recordingError)}},Skylink.prototype._inRoomHandler=function(message){var self=this;log.log(["Server",null,message.type,"User is now in the room and functionalities are now available. Config received:"],message.pc_config),self._room.connection.peerConfig=self._setIceServers(message.pc_config),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.ENFORCE_OFFERER?2e15:-2e15),self._trigger("peerJoined",self._user.sid,self.getPeerInfo(),!0),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,self._user.sid);var streamId=null;self._streams.screenshare&&self._streams.screenshare.stream?(streamId=self._streams.screenshare.stream.id||self._streams.screenshare.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.screenshare.stream,!0,self.getPeerInfo(),!0,streamId)):self._streams.userMedia&&self._streams.userMedia.stream&&(streamId=self._streams.userMedia.stream.id||self._streams.userMedia.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.userMedia.stream,!0,self.getPeerInfo(),!1,streamId));var enterMsg={type:self._SIG_MESSAGE_TYPE.ENTER,mid:self._user.sid,rid:self._room.id,agent:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._enterHandler=function(message){var self=this,targetMid=message.mid,isNewPeer=!1,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),receiveOnly:self.getPeerInfo().config.receiveOnly,os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg),isNewPeer&&self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._restartHandler=function(message){var self=this,targetMid=message.mid,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg)}};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._offerHandler=function(message){var self=this,targetMid=message.mid,pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for offer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}log.log([targetMid,null,message.type,"Received offer from peer. Session description:"],clone(message));var offer={type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};return log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],offer),offer.sdp=self._removeSDPFilteredCandidates(targetMid,offer),offer.sdp=self._setSDPCodec(targetMid,offer),offer.sdp=self._setSDPBitrate(targetMid,offer),offer.sdp=self._setSDPCodecParams(targetMid,offer),offer.sdp=self._removeSDPCodecs(targetMid,offer),offer.sdp=self._removeSDPREMBPackets(targetMid,offer),offer.sdp=self._handleSDPConnectionSettings(targetMid,offer,"remote"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,null,message.type,'Peer connection state is not in "stable" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.resend}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),void pc.setRemoteDescription(new RTCSessionDescription(offer),function(){log.debug([targetMid,"RTCSessionDescription",message.type,"Remote description set"]),pc.setOffer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.OFFER,targetMid),self._addIceCandidateFromQueue(targetMid),self._doAnswer(targetMid)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,offer:offer})}))},Skylink.prototype._candidateHandler=function(message){var targetMid=message.mid;if(!message.candidate&&!message.id)return void log.warn([targetMid,"RTCIceCandidate",null,"Received invalid ICE candidate message ->"],message);var canId="can-"+(new Date).getTime(),candidateType=message.candidate.split(" ")[7]||"",candidate=new RTCIceCandidate({sdpMLineIndex:message.label,candidate:message.candidate,sdpMid:message.id});if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Received ICE candidate ->"],candidate),this._peerEndOfCandidatesCounter[targetMid]=this._peerEndOfCandidatesCounter[targetMid]||{},this._peerEndOfCandidatesCounter[targetMid].len=this._peerEndOfCandidatesCounter[targetMid].len||0,this._peerEndOfCandidatesCounter[targetMid].hasSet=!1,this._peerEndOfCandidatesCounter[targetMid].len++,this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.RECEIVED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!this._peerConnections[targetMid]||this._peerConnections[targetMid].signalingState===this.PEER_CONNECTION_STATE.CLOSED)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed.")),void this._signalingEndOfCandidates(targetMid);if(this._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._forceTURN)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping received ICE candidate as it matches ICE candidate filtering flag ->"],candidate),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Dropping of processing ICE candidate as it matches ICE candidate filtering flag.")),void this._signalingEndOfCandidates(targetMid);log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Not dropping received ICE candidate as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured ->"],candidate)}this._peerConnections[targetMid].remoteDescription&&this._peerConnections[targetMid].remoteDescription.sdp&&this._peerConnections[targetMid].localDescription&&this._peerConnections[targetMid].localDescription.sdp?this._addIceCandidate(targetMid,canId,candidate):this._addIceCandidateToQueue(targetMid,canId,candidate),this._signalingEndOfCandidates(targetMid),this._gatheredCandidates[targetMid]||(this._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),this._gatheredCandidates[targetMid].receiving[candidateType].push({sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex,candidate:candidate.candidate})},Skylink.prototype._answerHandler=function(message){var self=this,targetMid=message.mid;log.log([targetMid,null,message.type,"Received answer from peer. Session description:"],clone(message));var pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for answer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}var answer={type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};return log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],answer),answer.sdp=self._removeSDPFilteredCandidates(targetMid,answer),answer.sdp=self._setSDPCodec(targetMid,answer),answer.sdp=self._setSDPBitrate(targetMid,answer),answer.sdp=self._setSDPCodecParams(targetMid,answer),answer.sdp=self._removeSDPCodecs(targetMid,answer),answer.sdp=self._removeSDPREMBPackets(targetMid,answer),answer.sdp=self._handleSDPConnectionSettings(targetMid,answer,"remote"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?void log.warn([targetMid,null,message.type,'Peer connection state is not in "have-local-offer" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.restart}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),void pc.setRemoteDescription(new RTCSessionDescription(answer),function(){log.debug([targetMid,null,message.type,"Remote description set"]),pc.setAnswer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ANSWER,targetMid),self._addIceCandidateFromQueue(targetMid),self._peerMessagesStamps[targetMid]&&(self._peerMessagesStamps[targetMid].hasRestart=!1),self._dataChannels[targetMid]&&(-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))},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,answer:answer})}))},Skylink.prototype._isLowerThanVersion=function(agentVer,requiredVer){for(var partsA=(agentVer||"").split("."),partsB=(requiredVer||"").split("."),i=0;i0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for sendStream() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream);else{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"===window.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"===window.webrtcDetectedBrowser?(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio=getUserMediaAudioSettings):useMediaSource.indexOf("audio")>-1&&useMediaSource.indexOf("tab")>-1&&(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio={})),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if(hasDefaultAudioTrack||!enableAudioSettings)return void self._onStreamAccessSuccess(stream,settings,!0,!1);settings.getUserMediaSettings.audio=getUserMediaAudioSettings,navigator.getUserMedia({audio:getUserMediaAudioSettings},function(audioStream){try{audioStream.addTrack(stream.getVideoTracks()[0]),self.once("mediaAccessSuccess",function(){self._streams.screenshare.streamClone=stream},function(stream,isScreensharing){return isScreensharing}),self._onStreamAccessSuccess(audioStream,settings,!0,!1)}catch(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.shareScreen)},Skylink.prototype.stopScreen=function(){this._streams.screenshare&&(this._stopStreams({screenshare:!0}),this._inRoom&&(this._streams.userMedia&&this._streams.userMedia.stream&&(this._trigger("incomingStream",this._user.sid,this._streams.userMedia.stream,!0,this.getPeerInfo(),!1,this._streams.userMedia.stream.id||this._streams.userMedia.stream.label),this._trigger("peerUpdated",this._user.sid,this.getPeerInfo(),!0)),this._refreshPeerConnection(Object.keys(this._peerConnections),{},!1)))},Skylink.prototype._muteStreams=function(){var self=this,hasVideo=!1,hasAudio=!1,muteFn=function(stream){for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",self._streamsMutedSettings),{hasVideo:hasVideo,hasAudio:hasAudio}},Skylink.prototype._stopStreams=function(options){var self=this,stopFn=function(stream){var streamId=stream.id||stream.label;log.debug([null,"MediaStream",streamId,"Stopping Stream ->"],stream);try{for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",options)},Skylink.prototype._parseStreamSettings=function(options){var settings={settings:{audio:!1,video:!1},mutedSettings:{shouldAudioMuted:!1,shouldVideoMuted:!1},getUserMediaSettings:{audio:!1,video:!1}};return options.audio&&(settings.settings.audio={stereo:!1,exactConstraints:!!options.useExactConstraints,echoCancellation:!0},settings.getUserMediaSettings.audio={echoCancellation:!0},"object"==typeof options.audio&&("boolean"==typeof options.audio.stereo&&(settings.settings.audio.stereo=options.audio.stereo),"boolean"==typeof options.audio.useinbandfec&&(settings.settings.audio.useinbandfec=options.audio.useinbandfec),"boolean"==typeof options.audio.usedtx&&(settings.settings.audio.usedtx=options.audio.usedtx),"number"==typeof options.audio.maxplaybackrate&&options.audio.maxplaybackrate>=8e3&&options.audio.maxplaybackrate<=48e3&&(settings.settings.audio.maxplaybackrate=options.audio.maxplaybackrate),"boolean"==typeof options.audio.mute&&(settings.mutedSettings.shouldAudioMuted=options.audio.mute),"edge"!==window.webrtcDetectedBrowser&&("boolean"==typeof options.audio.echoCancellation&&(settings.settings.audio.echoCancellation=options.audio.echoCancellation,settings.getUserMediaSettings.audio.echoCancellation=options.audio.echoCancellation),Array.isArray(options.audio.optional)&&(settings.settings.audio.optional=clone(options.audio.optional),settings.getUserMediaSettings.audio.optional=clone(options.audio.optional)),options.audio.deviceId&&"string"==typeof options.audio.deviceId&&"firefox"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,settings.getUserMediaSettings.audio.deviceId=options.useExactConstraints?{exact:options.audio.deviceId}:{ideal:options.audio.deviceId}))),"edge"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio=!0)),options.video&&(settings.settings.video={resolution:clone(this.VIDEO_RESOLUTION.VGA),screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video={},"object"==typeof options.video?("boolean"==typeof options.video.mute&&(settings.mutedSettings.shouldVideoMuted=options.video.mute),Array.isArray(options.video.optional)&&(settings.settings.video.optional=clone(options.video.optional),settings.getUserMediaSettings.video.optional=clone(options.video.optional)),options.video.deviceId&&"string"==typeof options.video.deviceId&&"firefox"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,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&&!self._isUsingPlugin)&&(settings.settings.video.frameRate=options.video.frameRate,settings.getUserMediaSettings.video.frameRate="object"==typeof settings.settings.video.frameRate?settings.settings.video.frameRate:options.useExactConstraints?{exact:settings.settings.video.frameRate}:{max:settings.settings.video.frameRate}),options.video.facingMode&&["string","object"].indexOf(typeof options.video.facingMode)>-1&&self._isUsingPlugin&&(settings.settings.video.facingMode=options.video.facingMode,settings.getUserMediaSettings.video.facingMode="object"==typeof settings.settings.video.facingMode?settings.settings.video.facingMode:options.useExactConstraints?{exact:settings.settings.video.facingMode}:{max:settings.settings.video.facingMode})):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"===window.webrtcDetectedBrowser&&(settings.settings.video={screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video=!0)),settings},Skylink.prototype._onStreamAccessSuccess=function(stream,settings,isScreenSharing,isAudioFallback){var self=this,streamId=stream.id||stream.label,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(window.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"===window.webrtcDetectedBrowser?stream.endedInterval=setInterval(function(){void 0===stream.recordedTime&&(stream.recordedTime=0),stream.recordedTime===stream.currentTime?(clearInterval(stream.endedInterval),self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])):stream.recordedTime=stream.currentTime},1e3):stream.onended=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},settings.settings.audio&&0===stream.getAudioTracks().length||settings.settings.video&&0===stream.getVideoTracks().length){var tracksNotSameError="Expected audio tracks length with "+(settings.settings.audio?"1":"0")+" and video tracks length with "+(settings.settings.video?"1":"0")+" but received audio tracks length with "+stream.getAudioTracks().length+" and video tracks length with "+stream.getVideoTracks().length;log.warn([null,"MediaStream",streamId,tracksNotSameError]);var requireAudio=!!settings.settings.audio,requireVideo=!!settings.settings.video;settings.settings.audio&&0===stream.getAudioTracks().length&&(settings.settings.audio=!1),settings.settings.video&&0===stream.getVideoTracks().length&&(settings.settings.video=!1),self._trigger("mediaAccessFallback",{error:new Error(tracksNotSameError),diff:{video:{expected:requireVideo?1:0,received:stream.getVideoTracks().length},audio:{expected:requireAudio?1:0,received:stream.getAudioTracks().length}}},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKED,!!isScreenSharing,!!isAudioFallback,streamId)}self._streams[isScreenSharing?"screenshare":"userMedia"]={stream:stream,settings:settings.settings,constraints:settings.getUserMediaSettings},self._muteStreams(),self._trigger("mediaAccessSuccess",stream,!!isScreenSharing,!!isAudioFallback,streamId)},Skylink.prototype._onStreamAccessError=function(error,settings,isScreenSharing){var self=this;if(!isScreenSharing&&settings.settings.audio&&settings.settings.video&&self._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},function(error){log.error("Failed fallbacking to retrieve audio only Stream ->",error),self._trigger("mediaAccessError",error,!1,!0),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.ERROR,!1,!0)});log.error("Failed retrieving "+(isScreenSharing?"screensharing":"camera")+" Stream ->",error),self._trigger("mediaAccessError",error,!!isScreenSharing,!1)},Skylink.prototype._onRemoteStreamAdded=function(targetMid,stream,isScreenSharing){var self=this;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1)},Skylink.prototype._addLocalMediaStreams=function(peerId){var self=this;try{log.log([peerId,null,null,"Adding local stream"]);var pc=self._peerConnections[peerId],offerToReceiveAudio=(self._peerInformations[peerId],self._peerInformations[peerId],!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-1?log.warn([peerId,null,null,"Not re-adding stream as LocalMediaStream is already added"],error):log.error([peerId,null,null,"Failed adding local stream"],error)}},Skylink.prototype._handleEndedStreams=function(peerId,checkStreamId){var self=this;self._streamsSession[peerId]=self._streamsSession[peerId]||{};var renderEndedFn=function(streamId){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){var codecsList=sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codecName+"/"+(samplingRate?samplingRate+("audio"===type?"[/]*.*":".*"):".*")+"\r\n","gi"));if(Array.isArray(codecsList)&&codecsList.length>0)for(var i=0;i0){for(var fmtpParts=(fmtpLine[0].split("a=fmtp:"+payload+" ")[1]||"").replace(/ /g,"").replace(/\r\n/g,"").split(";"),j=0;j0){if(0===sdpLines[i].indexOf("m="))break;0===sdpLines[i].indexOf("c=")?cLineIndex=i:0!==sdpLines[i].indexOf("b=AS:")&&0!==sdpLines[i].indexOf("b:TIAS:")||(sdpLines.splice(i,1),i--)}return"number"==typeof bw&&bw>0?-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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(this._peerInformations[targetMid],this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],compareB.join(" ")),sdpLines.splice(j,0,compareB.join(" ")),j++,mLineIndex++)}for(;this._sdpSessions[targetMid].remote.mLines[mLineIndex+1];){mLineIndex++;var appendIndex=sdpLines.length;sdpLines[appendIndex-1].replace(/\s/gi,"")||(appendIndex-=1);var parts=(this._sdpSessions[targetMid].remote.mLines[mLineIndex]||"").split(" ");parts[1]=0,log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending later rejected m= line ->"],parts.join(" ")),sdpLines.splice(appendIndex,0,parts.join(" "))}}return"edge"!==window.webrtcDetectedBrowser||sessionDescription.type!==this.HANDSHAKE_PROGRESS.OFFER||sdpLines[sdpLines.length-1].replace(/\s/gi,"")||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing last empty space for Edge browsers"]),sdpLines.splice(sdpLines.length-1,1)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "'+codec+'" as it does not exists.']);for(var i=0;i'],payload),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=fmtp:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:\\d+ rtx\\/\\d+\\r\\na=fmtp:\\d+ apt="+payload+"\\r\\n","g"),"");for(var sdpLines=sessionDescription.sdp.split("\r\n"),j=0;j=3&&parts.splice(parts.indexOf(payload),1),sdpLines[j]=parts.join(" ");break}sessionDescription.sdp=sdpLines.join("\r\n")}};return this._disableVideoFecCodecs&&(this._hasMCU?log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "ulpfec" or "red" codecs as connected to MCU to prevent connectivity issues.']):(parseFn("video","red"),parseFn("video","ulpfec"))),this._disableComfortNoiseCodec&&audioSettings&&"object"==typeof audioSettings&&audioSettings.stereo&&parseFn("audio","CN"),"edge"===window.webrtcDetectedBrowser&&"edge"!==(((this._peerInformations[targetMid]||{}).agent||{}).name||"unknown").name&&(sessionDescription.sdp=sessionDescription.sdp.replace(/a=rtcp-fb:.*\ x-message\ .*\r\n/gi,"")),sessionDescription.sdp},Skylink.prototype._removeSDPREMBPackets=function(targetMid,sessionDescription){return this._disableREMB?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing REMB packets."]),sessionDescription.sdp.replace(/a=rtcp-fb:\d+ goog-remb\r\n/g,"")):sessionDescription.sdp},Skylink.prototype._getSDPSelectedCodec=function(targetMid,sessionDescription,type,beSilentOnLogs){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},Skylink.prototype._removeSDPFilteredCandidates=function(targetMid,sessionDescription){return"MCU"===targetMid&&sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER&&"firefox"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=sessionDescription.sdp.replace(/ generation 0/g,""),sessionDescription.sdp=sessionDescription.sdp.replace(/ udp /g," UDP ")),this._forceTURN&&this._hasMCU?(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not filtering ICE candidates as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured"]),sessionDescription.sdp):(this._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._filterCandidatesType.relay&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "relay" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*relay.*\r\n/g,"")),sessionDescription.sdp)},Skylink.prototype._getCodecsSupport=function(callback){var self=this;if(self._currentCodecSupport)return void callback(null);self._currentCodecSupport={audio:{},video:{}};try{if("edge"===window.webrtcDetectedBrowser){for(var codecs=RTCRtpSender.getCapabilities().codecs,i=0;i-1&&codecs[i].name){var codec=codecs[i].name.toLowerCase();self._currentCodecSupport[codecs[i].kind][codec]=codecs[i].clockRate+(codecs[i].numChannels>1?"/"+codecs[i].numChannels:"")}callback(null)}else{var pc=new RTCPeerConnection(null),offerConstraints={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveVideo:!0,OfferToReceiveAudio:!0}});try{var channel=pc.createDataChannel("test");self._binaryChunkType=channel.binaryType||self._binaryChunkType,self._binaryChunkType=self._binaryChunkType.toLowerCase().indexOf("array")>-1?self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER:self._binaryChunkType;for(var prop in self.DATA_TRANSFER_DATA_TYPE)if(self.DATA_TRANSFER_DATA_TYPE.hasOwnProperty(prop)&&self._binaryChunkType.toLowerCase()===self.DATA_TRANSFER_DATA_TYPE[prop].toLowerCase()){self._binaryChunkType=self.DATA_TRANSFER_DATA_TYPE[prop];break}}catch(e){}pc.createOffer(function(offer){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",i=0;i"],sdpLines[i]),self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE&&bundleLineIndex>-1&&0===mLineIndex&&("remote"===direction?sessionDescription.type===this.HANDSHAKE_PROGRESS.OFFER:sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER)){log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not removing rejected m="+mediaType+" line ->"],sdpLines[i]),settings.connection[mediaType]=!0,["audio","video"].indexOf(mediaType)>-1&&(settings.direction[mediaType].send=!1,settings.direction[mediaType].receive=!1);continue}if("edge"===window.webrtcDetectedBrowser){sdpLines.splice(i,1),i--;continue}if("remote"===direction||sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER){var parts=sdpLines[i].split(" ");parts[1]=0,sdpLines[i]=parts.join(" ");continue}}if("remote"!==direction||0!==sdpLines[i].indexOf("a=candidate:")||self.getPeerInfo(targetMid).config.enableIceTrickle||sdpLines[i+1]&&(0===sdpLines[i+1].indexOf("a=candidate:")||0===sdpLines[i+1].indexOf("a=end-of-candidates"))||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]),sdpLines.splice(i+1,0,"a=end-of-candidates"),i++),mediaType)if(settings.connection[mediaType]){if(0===sdpLines[i].indexOf("a=mid:"))bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||"");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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"undefined"!=typeof exports?module.exports={Skylink:Skylink,SkylinkLogs:SkylinkLogs}:globals?(globals.Skylink=Skylink,globals.SkylinkLogs=SkylinkLogs):window&&(window.Skylink=Skylink,window.SkylinkLogs=SkylinkLogs)}(this); \ No newline at end of file +(options.video.frameRate&&"object"==typeof options.video.frameRate||"number"==typeof options.video.frameRate&&!self._isUsingPlugin)&&(settings.settings.video.frameRate=options.video.frameRate,settings.getUserMediaSettings.video.frameRate="object"==typeof settings.settings.video.frameRate?settings.settings.video.frameRate:options.useExactConstraints?{exact:settings.settings.video.frameRate}:{max:settings.settings.video.frameRate}),options.video.facingMode&&["string","object"].indexOf(typeof options.video.facingMode)>-1&&self._isUsingPlugin&&(settings.settings.video.facingMode=options.video.facingMode,settings.getUserMediaSettings.video.facingMode="object"==typeof settings.settings.video.facingMode?settings.settings.video.facingMode:options.useExactConstraints?{exact:settings.settings.video.facingMode}:{max:settings.settings.video.facingMode})):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"===window.webrtcDetectedBrowser&&(settings.settings.video={screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video=!0)),settings},Skylink.prototype._onStreamAccessSuccess=function(stream,settings,isScreenSharing,isAudioFallback){var self=this,streamId=stream.id||stream.label,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(window.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"===window.webrtcDetectedBrowser?stream.endedInterval=setInterval(function(){void 0===stream.recordedTime&&(stream.recordedTime=0),stream.recordedTime===stream.currentTime?(clearInterval(stream.endedInterval),self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])):stream.recordedTime=stream.currentTime},1e3):stream.onended=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},settings.settings.audio&&0===stream.getAudioTracks().length||settings.settings.video&&0===stream.getVideoTracks().length){var tracksNotSameError="Expected audio tracks length with "+(settings.settings.audio?"1":"0")+" and video tracks length with "+(settings.settings.video?"1":"0")+" but received audio tracks length with "+stream.getAudioTracks().length+" and video tracks length with "+stream.getVideoTracks().length;log.warn([null,"MediaStream",streamId,tracksNotSameError]);var requireAudio=!!settings.settings.audio,requireVideo=!!settings.settings.video;settings.settings.audio&&0===stream.getAudioTracks().length&&(settings.settings.audio=!1),settings.settings.video&&0===stream.getVideoTracks().length&&(settings.settings.video=!1),self._trigger("mediaAccessFallback",{error:new Error(tracksNotSameError),diff:{video:{expected:requireVideo?1:0,received:stream.getVideoTracks().length},audio:{expected:requireAudio?1:0,received:stream.getAudioTracks().length}}},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKED,!!isScreenSharing,!!isAudioFallback,streamId)}self._streams[isScreenSharing?"screenshare":"userMedia"]={stream:stream,settings:settings.settings,constraints:settings.getUserMediaSettings},self._muteStreams(),self._trigger("mediaAccessSuccess",stream,!!isScreenSharing,!!isAudioFallback,streamId)},Skylink.prototype._onStreamAccessError=function(error,settings,isScreenSharing){var self=this;if(!isScreenSharing&&settings.settings.audio&&settings.settings.video&&self._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},function(error){log.error("Failed fallbacking to retrieve audio only Stream ->",error),self._trigger("mediaAccessError",error,!1,!0),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.ERROR,!1,!0)});log.error("Failed retrieving "+(isScreenSharing?"screensharing":"camera")+" Stream ->",error),self._trigger("mediaAccessError",error,!!isScreenSharing,!1)},Skylink.prototype._onRemoteStreamAdded=function(targetMid,stream,isScreenSharing){var self=this;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1)},Skylink.prototype._addLocalMediaStreams=function(peerId){var self=this;try{log.log([peerId,null,null,"Adding local stream"]);var pc=self._peerConnections[peerId],offerToReceiveAudio=(self._peerInformations[peerId],self._peerInformations[peerId],!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-1?log.warn([peerId,null,null,"Not re-adding stream as LocalMediaStream is already added"],error):log.error([peerId,null,null,"Failed adding local stream"],error)}},Skylink.prototype._handleEndedStreams=function(peerId,checkStreamId){var self=this;self._streamsSession[peerId]=self._streamsSession[peerId]||{};var renderEndedFn=function(streamId){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){var codecsList=sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codecName+"/"+(samplingRate?samplingRate+("audio"===type?"[/]*.*":".*"):".*")+"\r\n","gi"));if(Array.isArray(codecsList)&&codecsList.length>0)for(var i=0;i0){for(var fmtpParts=(fmtpLine[0].split("a=fmtp:"+payload+" ")[1]||"").replace(/ /g,"").replace(/\r\n/g,"").split(";"),j=0;j0){if(0===sdpLines[i].indexOf("m="))break;0===sdpLines[i].indexOf("c=")?cLineIndex=i:0!==sdpLines[i].indexOf("b=AS:")&&0!==sdpLines[i].indexOf("b:TIAS:")||(sdpLines.splice(i,1),i--)}return"number"==typeof bw&&bw>0?-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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(this._peerInformations[targetMid],this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],compareB.join(" ")),sdpLines.splice(j,0,compareB.join(" ")),j++,mLineIndex++)}for(;this._sdpSessions[targetMid].remote.mLines[mLineIndex+1];){mLineIndex++;var appendIndex=sdpLines.length;sdpLines[appendIndex-1].replace(/\s/gi,"")||(appendIndex-=1);var parts=(this._sdpSessions[targetMid].remote.mLines[mLineIndex]||"").split(" ");parts[1]=0,log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending later rejected m= line ->"],parts.join(" ")),sdpLines.splice(appendIndex,0,parts.join(" "))}}return"edge"!==window.webrtcDetectedBrowser||sessionDescription.type!==this.HANDSHAKE_PROGRESS.OFFER||sdpLines[sdpLines.length-1].replace(/\s/gi,"")||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing last empty space for Edge browsers"]),sdpLines.splice(sdpLines.length-1,1)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "'+codec+'" as it does not exists.']);for(var i=0;i'],payload),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=fmtp:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:\\d+ rtx\\/\\d+\\r\\na=fmtp:\\d+ apt="+payload+"\\r\\n","g"),"");for(var sdpLines=sessionDescription.sdp.split("\r\n"),j=0;j=3&&parts.splice(parts.indexOf(payload),1),sdpLines[j]=parts.join(" ");break}sessionDescription.sdp=sdpLines.join("\r\n")}};return this._disableVideoFecCodecs&&(this._hasMCU?log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "ulpfec" or "red" codecs as connected to MCU to prevent connectivity issues.']):(parseFn("video","red"),parseFn("video","ulpfec"))),this._disableComfortNoiseCodec&&audioSettings&&"object"==typeof audioSettings&&audioSettings.stereo&&parseFn("audio","CN"),"edge"===window.webrtcDetectedBrowser&&"edge"!==(((this._peerInformations[targetMid]||{}).agent||{}).name||"unknown").name&&(sessionDescription.sdp=sessionDescription.sdp.replace(/a=rtcp-fb:.*\ x-message\ .*\r\n/gi,"")),sessionDescription.sdp},Skylink.prototype._removeSDPREMBPackets=function(targetMid,sessionDescription){return this._disableREMB?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing REMB packets."]),sessionDescription.sdp.replace(/a=rtcp-fb:\d+ goog-remb\r\n/g,"")):sessionDescription.sdp},Skylink.prototype._getSDPSelectedCodec=function(targetMid,sessionDescription,type,beSilentOnLogs){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},Skylink.prototype._removeSDPFilteredCandidates=function(targetMid,sessionDescription){return"MCU"===targetMid&&sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER&&"firefox"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=sessionDescription.sdp.replace(/ generation 0/g,""),sessionDescription.sdp=sessionDescription.sdp.replace(/ udp /g," UDP ")),this._forceTURN&&this._hasMCU?(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not filtering ICE candidates as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured"]),sessionDescription.sdp):(this._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._filterCandidatesType.relay&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "relay" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*relay.*\r\n/g,"")),sessionDescription.sdp)},Skylink.prototype._getCodecsSupport=function(callback){var self=this;if(self._currentCodecSupport)return void callback(null);self._currentCodecSupport={audio:{},video:{}};try{if("edge"===window.webrtcDetectedBrowser){for(var codecs=RTCRtpSender.getCapabilities().codecs,i=0;i-1&&codecs[i].name){var codec=codecs[i].name.toLowerCase();self._currentCodecSupport[codecs[i].kind][codec]=codecs[i].clockRate+(codecs[i].numChannels>1?"/"+codecs[i].numChannels:"")}callback(null)}else{var pc=new RTCPeerConnection(null),offerConstraints={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveVideo:!0,OfferToReceiveAudio:!0}});try{var channel=pc.createDataChannel("test");self._binaryChunkType=channel.binaryType||self._binaryChunkType,self._binaryChunkType=self._binaryChunkType.toLowerCase().indexOf("array")>-1?self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER:self._binaryChunkType;for(var prop in self.DATA_TRANSFER_DATA_TYPE)if(self.DATA_TRANSFER_DATA_TYPE.hasOwnProperty(prop)&&self._binaryChunkType.toLowerCase()===self.DATA_TRANSFER_DATA_TYPE[prop].toLowerCase()){self._binaryChunkType=self.DATA_TRANSFER_DATA_TYPE[prop];break}}catch(e){}pc.createOffer(function(offer){ +for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",i=0;i"],sdpLines[i]),self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE&&bundleLineIndex>-1&&0===mLineIndex&&("remote"===direction?sessionDescription.type===this.HANDSHAKE_PROGRESS.OFFER:sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER)){log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not removing rejected m="+mediaType+" line ->"],sdpLines[i]),settings.connection[mediaType]=!0,["audio","video"].indexOf(mediaType)>-1&&(settings.direction[mediaType].send=!1,settings.direction[mediaType].receive=!1);continue}if("edge"===window.webrtcDetectedBrowser){sdpLines.splice(i,1),i--;continue}if("remote"===direction||sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER){var parts=sdpLines[i].split(" ");parts[1]=0,sdpLines[i]=parts.join(" ");continue}}if("remote"!==direction||0!==sdpLines[i].indexOf("a=candidate:")||self.getPeerInfo(targetMid).config.enableIceTrickle||sdpLines[i+1]&&(0===sdpLines[i+1].indexOf("a=candidate:")||0===sdpLines[i+1].indexOf("a=end-of-candidates"))||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]),sdpLines.splice(i+1,0,"a=end-of-candidates"),i++),mediaType)if(settings.connection[mediaType]){if(0===sdpLines[i].indexOf("a=mid:"))bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||"");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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"undefined"!=typeof exports?module.exports={Skylink:Skylink,SkylinkLogs:SkylinkLogs}:globals?(globals.Skylink=Skylink,globals.SkylinkLogs=SkylinkLogs):window&&(window.Skylink=Skylink,window.SkylinkLogs=SkylinkLogs)}(this); \ No newline at end of file diff --git a/source/room-init.js b/source/room-init.js index 25f4a147e..37976b20b 100644 --- a/source/room-init.js +++ b/source/room-init.js @@ -428,8 +428,9 @@ Skylink.prototype.generateUUID = function() { * @param {JSON} [options.codecParams.audio.opus]
    * Note that this is only applicable to OPUS audio codecs with a sampling rate of 48000 Hz (hertz). *
    The OPUS audio codec parameters to configure. - * @param {Boolean} [options.codecParams.audio.opus.stereo] The flag if OPUS audio codec stereo band - * should be configured for sending encoded audio data. + * @param {Boolean} [options.codecParams.audio.opus.stereo] The flag if OPUS audio codec is able to decode or receive stereo packets. + * When not provided, the default browser configuration is used. + * @param {Boolean} [options.codecParams.audio.opus.sprop-stereo] The flag if OPUS audio codec is sending stereo packets. * When not provided, the default browser configuration is used. * @param {Boolean} [options.codecParams.audio.opus.usedtx]
    * Note that this feature might not work depending on the browser support and implementation.
    @@ -828,6 +829,8 @@ Skylink.prototype.init = function(options, callback) { codecParams.audio.opus = { stereo: typeof options.codecParams.audio.opus.stereo === 'boolean' ? options.codecParams.audio.opus.stereo : null, + 'sprop-stereo': typeof options.codecParams.audio.opus['sprop-stereo'] === 'boolean' ? + options.codecParams.audio.opus['sprop-stereo'] : null, usedtx: typeof options.codecParams.audio.opus.usedtx === 'boolean' ? options.codecParams.audio.opus.usedtx : null, useinbandfec: typeof options.codecParams.audio.opus.useinbandfec === 'boolean' ? diff --git a/source/stream-sdp.js b/source/stream-sdp.js index f86702339..03e591cc9 100644 --- a/source/stream-sdp.js +++ b/source/stream-sdp.js @@ -64,7 +64,8 @@ Skylink.prototype._setSDPCodecParams = function(targetMid, sessionDescription) { // RFC: https://tools.ietf.org/html/draft-ietf-payload-rtp-opus-11 parseFn('audio', self.AUDIO_CODEC.OPUS, 48000, (function () { var opusOptions = {}; - var audioSettings = self.getPeerInfo().settings.audio; + var audioSettings = self._streams.screenshare ? self._streams.screenshare.settings.audio : + (self._streams.userMedia ? self._streams.userMedia.settings.audio : {}); audioSettings = audioSettings && typeof audioSettings === 'object' ? audioSettings : {}; if (typeof self._codecParams.audio.opus.stereo === 'boolean') { opusOptions.stereo = self._codecParams.audio.opus.stereo; From 12aac4c59a9069c1353cc1a6dcaef0eb3649f272 Mon Sep 17 00:00:00 2001 From: Leticia Choo Date: Tue, 18 Jul 2017 14:38:48 +0800 Subject: [PATCH 3/6] Release 0.6.24. --- README.md | 2 +- bower.json | 2 +- doc/classes/Skylink.html | 4 +- doc/data.json | 2 +- doc/files/source_data-channel.js.html | 4 +- doc/files/source_data-process.js.html | 4 +- doc/files/source_data-transfer.js.html | 4 +- doc/files/source_ice-candidate.js.html | 4 +- doc/files/source_ice-connection.js.html | 4 +- doc/files/source_peer-connection.js.html | 4 +- doc/files/source_peer-data.js.html | 4 +- doc/files/source_peer-handshake.js.html | 4 +- doc/files/source_peer-privileged.js.html | 4 +- doc/files/source_room-connection.js.html | 4 +- doc/files/source_room-init.js.html | 4 +- doc/files/source_skylink-events.js.html | 4 +- doc/files/source_socket-channel.js.html | 4 +- doc/files/source_socket-message.js.html | 4 +- doc/files/source_stream-media.js.html | 4 +- doc/files/source_stream-sdp.js.html | 4 +- doc/index.html | 6 +- package.json | 2 +- publish/skylink.complete.js | 94 +++++++++++++----------- publish/skylink.complete.min.js | 32 ++++---- publish/skylink.debug.js | 4 +- publish/skylink.min.js | 4 +- 26 files changed, 111 insertions(+), 105 deletions(-) diff --git a/README.md b/README.md index d8b090b14..53bdf2172 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ You can raise tickets on [our support portal](http://support.temasys.io) or on [ ##### Current versions and stability We recommend that you always use the latest versions of the Temasys Web SDK as WebRTC is still evolving and we adapt to changes very frequently. -[Latest version: `0.6.23`](https://github.com/Temasys/SkylinkJS/releases/tag/0.6.23). +[Latest version: `0.6.24`](https://github.com/Temasys/SkylinkJS/releases/tag/0.6.24). #### Noted Issues and Solutions ##### Installing `0.6.3` - `0.6.10` versions in NPM diff --git a/bower.json b/bower.json index afad4da0d..26c8e9730 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "skylinkjs", "description": "WebRTC real-time video conversation library", - "version": "0.6.23", + "version": "0.6.24", "homepage": "https://temasys.io", "author": { "name": "Temasys Communications Pte. Ltd.", diff --git a/doc/classes/Skylink.html b/doc/classes/Skylink.html index 29f56e21f..3b150626e 100644 --- a/doc/classes/Skylink.html +++ b/doc/classes/Skylink.html @@ -2,7 +2,7 @@ - SkylinkJS 0.6.23 + SkylinkJS 0.6.24 @@ -33,7 +33,7 @@ - Version: 0.6.23 + Version: 0.6.24