@reactoo/watchtogether-sdk-js 2.5.71 → 2.5.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @reactoo/watchtogether-sdk-js
3
- * @version 2.5.71
3
+ * @version 2.5.74
4
4
  */
5
5
  (function webpackUniversalModuleDefinition(root, factory) {
6
6
  if(typeof exports === 'object' && typeof module === 'object')
@@ -9307,7 +9307,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9307
9307
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9308
9308
 
9309
9309
  "use strict";
9310
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n/* harmony import */ var _wt_emitter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../wt-emitter */ \"./src/modules/wt-emitter.js\");\n\n\n\nconst syncModule = function () {\n let {\n room,\n emitter\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n //SYNC VARS\n let _emitter = Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])();\n\n let _playerInterface = null;\n let _propagateMaster = false;\n let _playerInterfaceOptions = {\n type: 'none',\n ignoreBufferedTimeRanges: true,\n disableFastSeek: false\n };\n const syncDefaultWaitTime = 60000;\n const syncShortWaitTime = 10000;\n const maxSyncThreshold = 0.5;\n const maxSyncTries = 3;\n const waitForPlayingEventAfterSeek = 5000;\n const fastForwardThreshold = 4;\n let currentSyncRetry = 0;\n let syncWaitId = null;\n let syncNextWaitTime = null;\n let stopFlag = false;\n let isSyncing = false;\n let safeSpace = 2;\n let playbackRate = 2;\n let isPlaying = false;\n let isPreloading = true;\n let isProgrammaticallySeeked = false;\n\n const startSyncLoop = () => {\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n if (!_playerInterfaceOptions.type === 'push') {\n const loop = () => {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(() => {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n } else {\n const loop2 = () => {\n seekForward().then(() => {\n setNextWaitTime(false);\n }).catch(e => {\n setNextWaitTime(true);\n console.log('Sync failed', e);\n });\n syncWaitId = setTimeout(loop2, syncNextWaitTime);\n };\n\n loop2();\n } //TODO: push sync\n\n };\n\n const stopSyncLoop = doNotResetRetryCount => {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n\n if (!doNotResetRetryCount) {\n currentSyncRetry = 0;\n }\n\n stopFlag = true;\n };\n\n const restartSyncLoop = () => {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n const setNextWaitTime = function () {\n let didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n const sync = () => {\n return getSyncData().then(syncData => {\n if (syncData.isMaster) {\n if (_playerInterface.isPaused) _playerInterface.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (_propagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n const syncStartTime = Date.now();\n const {\n position,\n realPosition,\n isBufferSufficient\n } = _playerInterface.getTimeDifference ? _playerInterface.getTimeDifference(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping) : getTimeDifference(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping);\n\n if (position && Math.abs(position) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null && !isNaN(position)) {\n return seekBy(position).then(() => {\n const seekDuration = Date.now() - syncStartTime;\n const {\n position,\n realPosition,\n isBufferSufficient\n } = _playerInterface.getTimeDifference ? _playerInterface.getTimeDifference(syncData.masterFragmentSn, syncData.masterFragmentPos + seekDuration, syncData.ping) : getTimeDifference(syncData.masterFragmentSn, syncData.masterFragmentPos + seekDuration, syncData.ping);\n const syncPrecision = Math.abs(realPosition);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration / 1000, \" seconds\"));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n const didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(e => {\n room._log(\"Seek failed: \", e);\n\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n room._log(\"Position in not a number: \", position);\n\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(e => {\n room._log(\"getSyncData() failed: \", e);\n\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n const handleAddLocalParticipant = () => {\n if (_propagateMaster) {\n propagateMasterFunc();\n }\n\n if (_playerInterface.isPaused === false) {\n _emitter.once('timeupdate', restartSyncLoop);\n }\n };\n\n const handleAddRemoteParticipant = () => {\n if (_propagateMaster) {\n propagateMasterFunc();\n }\n };\n\n const isConnected = () => {\n return room._isDataChannelOpen && room.isConnected;\n };\n\n const parseDataEvents = function () {\n let msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(() => {});\n }\n };\n\n const getCurrentPlayerPosition = () => {\n let position = _playerInterface.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n const getTimeDifference = (fragmentSn, fragmentPos, ping) => {\n let seekRanges = _playerInterface.buffered;\n let position = (fragmentPos + ping / 2) / 1000;\n let currentPlayerPosition = getCurrentPlayerPosition() / 1000;\n\n if (seekRanges && !_playerInterfaceOptions.ignoreBufferedTimeRanges) {\n let seekRange = {};\n\n for (let i = 0; i < seekRanges.length; i++) {\n let _c_start = seekRanges.start(i);\n\n let _c_end = seekRanges.end(i);\n\n if (!seekRange.start || _c_start < seekRange.start) {\n seekRange.start = _c_start;\n }\n\n if (!seekRange.end || _c_end > seekRange.end) {\n seekRange.end = _c_end;\n }\n }\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position: position - currentPlayerPosition,\n realPosition: position - currentPlayerPosition,\n isBufferSufficient: true\n };\n } else if (position < seekRange.start) {\n room._log(\"Syncing to \".concat(seekRange.start, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.start + 0.5 - currentPlayerPosition,\n realPosition: position - currentPlayerPosition,\n isBufferSufficient: false\n };\n } else if (position > seekRange.end) {\n room._log(\"Syncing to \".concat(seekRange.end, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.end - 0.5 - currentPlayerPosition,\n realPosition: position - currentPlayerPosition,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n isBufferSufficient: false\n };\n } else {\n return {\n position: position - currentPlayerPosition,\n realPosition: position - currentPlayerPosition,\n isBufferSufficient: true\n };\n }\n };\n\n const seekForward = () => {\n return new Promise((resolve, reject) => {\n let diff = _playerInterface.buffered.end(0) - _playerInterface.currentTime;\n\n let diff_target = diff - safeSpace;\n\n let __ = () => {\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n isSyncing = false;\n reject('Stalled');\n };\n\n console.log('Users stream is behind behind live by:', diff);\n\n if (diff_target > 0) {\n _emitter.once('stalled', __);\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(() => {\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n isSyncing = false;\n\n _emitter.off('stalled', __);\n\n resolve();\n }, diff_target * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n isSyncing = true;\n\n _playerInterface.setPlaybackRate(playbackRate);\n } else {\n resolve();\n }\n });\n };\n\n const seekBy = time => {\n return new Promise((resolve, reject) => {\n if (_playerInterface.currentTime !== time) {\n if (time > 0 && time < fastForwardThreshold && !_playerInterfaceOptions.disableFastSeek) {\n room._log(\"Fast forward to seek...\");\n\n let wasPaused = false;\n\n let _handleFailed = () => {\n if (wasPaused) {\n _playerInterface.pause();\n }\n\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n let _fastForward = () => {\n isProgrammaticallySeeked = true;\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(() => {\n _emitter.off('stalled', _handleFailed);\n\n if (wasPaused && _playerInterface.isVod) {\n _playerInterface.pause();\n }\n\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n resolve();\n }, time * 1000 / (playbackRate - 1), 20);\n\n _playerInterface.setPlaybackRate(playbackRate);\n };\n\n _emitter.once('stalled', _handleFailed);\n\n if (_playerInterface.isPaused) {\n wasPaused = true;\n\n _playerInterface.play().then(() => {\n _fastForward();\n }).catch(_handleFailed);\n } else {\n _fastForward();\n }\n } else {\n room._log(\"Jump to seek...\");\n\n let currentTimestamp = Date.now();\n let __failsafeId = null;\n\n let _resolve = () => {\n clearTimeout(__failsafeId);\n __failsafeId = null;\n isProgrammaticallySeeked = false;\n\n room._log(\"It took the player \".concat((Date.now() - currentTimestamp) / 1000, \" seconds to seek \"));\n\n resolve();\n };\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _emitter.once('playing', _resolve);\n\n __failsafeId = setTimeout(_resolve, waitForPlayingEventAfterSeek);\n\n _playerInterface.seek(_playerInterface.currentTime + time);\n }\n } else resolve();\n });\n };\n\n const seekTo = time => {\n return new Promise((resolve, reject) => {\n if (_playerInterface.currentTime !== time) {\n let diff = time - _playerInterface.currentTime;\n\n if (_playerInterface.currentTime < time && diff < fastForwardThreshold && !_playerInterfaceOptions.disableFastSeek) {\n room._log(\"Fast forward to seek...\");\n\n let wasPaused = false;\n\n let _handleFailed = () => {\n if (wasPaused) {\n _playerInterface.pause();\n }\n\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n let _fastForward = () => {\n isProgrammaticallySeeked = true;\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(() => {\n _emitter.off('stalled', _handleFailed);\n\n if (wasPaused && _playerInterface.isVod) {\n _playerInterface.pause();\n }\n\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n\n _playerInterface.setPlaybackRate(playbackRate);\n };\n\n _emitter.once('stalled', _handleFailed);\n\n if (_playerInterface.isPaused) {\n wasPaused = true;\n\n _playerInterface.play().then(() => {\n _fastForward();\n }).catch(_handleFailed);\n } else {\n _fastForward();\n }\n } else {\n room._log(\"Jump to seek...\");\n\n let currentTimestamp = Date.now();\n let __failsafeId = null;\n\n let _resolve = () => {\n clearTimeout(__failsafeId);\n __failsafeId = null;\n isProgrammaticallySeeked = false;\n\n room._log(\"It took the player \".concat((Date.now() - currentTimestamp) / 1000, \" seconds to seek \"));\n\n resolve();\n };\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _emitter.once('playing', _resolve);\n\n __failsafeId = setTimeout(_resolve, waitForPlayingEventAfterSeek);\n\n _playerInterface.seek(time);\n }\n } else resolve();\n });\n };\n\n const handlePlaying = () => {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _playerInterface.isPaused;\n isPlaying = !_playerInterface.isPaused;\n };\n\n const handlePause = () => {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPlaying = !_playerInterface.isPaused;\n };\n\n const handleBuffering = () => {\n room._log('handleBuffering');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop(true);\n clientPaused().catch(() => {});\n isPreloading = _playerInterface.isPaused;\n }\n };\n\n const roomSyncSend = slaveId => {\n var _playerInterface2;\n\n if (!_playerInterface) {\n room._log(\"I've been asked for position even if we don't have player attached.\\n Does it mean I'm the master?\");\n\n return Promise.resolve();\n }\n\n var fragmentData = ((_playerInterface2 = _playerInterface) === null || _playerInterface2 === void 0 ? void 0 : _playerInterface2.currentFragment) || {\n fragment: String(\"0\"),\n fragment_pos: Number(parseInt(getCurrentPlayerPosition()))\n };\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentData.fragment, \" # \").concat(fragmentData.fragment_pos));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId),\n ...fragmentData\n }\n });\n };\n\n const getSyncData = () => {\n var _playerInterface3;\n\n room._log('Sending roomSync request');\n\n let roomId = room.roomId;\n var fragmentData = ((_playerInterface3 = _playerInterface) === null || _playerInterface3 === void 0 ? void 0 : _playerInterface3.currentFragment) || {\n fragment: String(\"0\"),\n fragment_pos: Number(parseInt(getCurrentPlayerPosition()))\n };\n return new Promise((resolve, reject) => {\n let now = new Date().getTime();\n let ping = null;\n let sid = setTimeout(() => {\n room.off('data', fn, this);\n reject('Timeout');\n }, 3000);\n let body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n ...fragmentData\n };\n\n let fn = msg => {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, this);\n room.sendMessage(room.handleId, {\n body\n }).then(fn).catch(e => {\n room.off('data', fn, this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n const clientPaused = () => {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n const propagateMasterFunc = () => {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function () {\n let {\n playerInterface,\n propagateMaster = false\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _playerInterface = playerInterface;\n _playerInterfaceOptions = { ..._playerInterfaceOptions,\n ...(_playerInterface.syncSettings || {})\n };\n _propagateMaster = propagateMaster;\n\n room._log('Interface options passed: ', _playerInterface.syncSettings || {});\n\n room._log('All interface options: ', _playerInterfaceOptions);\n\n if (_playerInterfaceOptions.type === 'none') {\n room._log('Sync module has been disabled via type:none');\n\n return;\n } // if(_playerInterfaceOptions.type === 'push') {\n // \troom._log('Push sync is not implemented in this sync module yet');\n // \treturn;\n // }\n\n\n if (_playerInterface.isVod) {\n room._log('VOD sync is not implemented in this sync module yet');\n\n return;\n }\n\n playerInterface.addHandlers({\n handlePause: event => {\n room._log('handlePause');\n\n _emitter.emit('pause', event);\n },\n handlePlaying: event => {\n room._log('handlePlaying');\n\n _emitter.emit('playing', event);\n },\n handleBuffering: event => {\n room._log('handleBuffering');\n\n _emitter.emit('buffering', event);\n\n _emitter.emit('stalled', event);\n },\n handleTimeupdate: event => {\n room._log('handleTimeupdate');\n\n _emitter.emit('timeupdate', event);\n }\n });\n isPlaying = _playerInterface.isPaused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (_propagateMaster) {\n propagateMasterFunc().catch(() => {});\n }\n\n if (_playerInterface.isPaused === false) {\n _emitter.once('timeupdate', restartSyncLoop);\n }\n\n _emitter.on('buffering', handleBuffering);\n\n _emitter.on('playing', handlePlaying);\n\n _emitter.on('pause', handlePause);\n },\n destroy: () => {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n _playerInterface = null;\n\n _emitter.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncModule);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-module.js?");
9310
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n/* harmony import */ var _wt_emitter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../wt-emitter */ \"./src/modules/wt-emitter.js\");\n\n\n\nconst syncModule = function () {\n let {\n room,\n emitter\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n //SYNC VARS\n let _emitter = Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])();\n\n let _playerInterface = null;\n let _propagateMaster = false;\n let _playerInterfaceOptions = {\n type: 'none',\n ignoreBufferedTimeRanges: true,\n disableFastSeek: false\n };\n const syncDefaultWaitTime = 60000;\n const syncShortWaitTime = 10000;\n const maxSyncThreshold = 0.5;\n const maxSyncTries = 3;\n const waitForPlayingEventAfterSeek = 5000;\n const fastForwardThreshold = 4;\n let currentSyncRetry = 0;\n let syncWaitId = null;\n let syncNextWaitTime = null;\n let stopFlag = false;\n let isSyncing = false;\n let safeSpace = 2;\n let playbackRate = 2;\n let isPlaying = false;\n let isPreloading = true;\n let isProgrammaticallySeeked = false;\n\n const startSyncLoop = () => {\n if (!isConnected() && _playerInterfaceOptions.type !== 'push') {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n if (_playerInterfaceOptions.type !== 'push') {\n const loop = () => {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(() => {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n } else {\n const loop2 = () => {\n seekForward().then(() => {\n setNextWaitTime(false);\n }).catch(e => {\n setNextWaitTime(true);\n console.log('Sync failed', e);\n });\n syncWaitId = setTimeout(loop2, syncNextWaitTime);\n };\n\n loop2();\n }\n };\n\n const stopSyncLoop = doNotResetRetryCount => {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n\n if (!doNotResetRetryCount) {\n currentSyncRetry = 0;\n }\n\n stopFlag = true;\n };\n\n const restartSyncLoop = () => {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n const setNextWaitTime = function () {\n let didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n const sync = () => {\n return getSyncData().then(syncData => {\n if (syncData.isMaster) {\n if (_playerInterface.isPaused) _playerInterface.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (_propagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n const syncStartTime = Date.now();\n const {\n position,\n realPosition,\n isBufferSufficient\n } = _playerInterface.getTimeDifference ? _playerInterface.getTimeDifference(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping) : getTimeDifference(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping);\n\n if (position && Math.abs(position) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null && !isNaN(position)) {\n return seekBy(position).then(() => {\n const seekDuration = Date.now() - syncStartTime;\n const {\n position,\n realPosition,\n isBufferSufficient\n } = _playerInterface.getTimeDifference ? _playerInterface.getTimeDifference(syncData.masterFragmentSn, syncData.masterFragmentPos + seekDuration, syncData.ping) : getTimeDifference(syncData.masterFragmentSn, syncData.masterFragmentPos + seekDuration, syncData.ping);\n const syncPrecision = Math.abs(realPosition);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration / 1000, \" seconds\"));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n const didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(e => {\n room._log(\"Seek failed: \", e);\n\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n room._log(\"Position in not a number: \", position);\n\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(e => {\n room._log(\"getSyncData() failed: \", e);\n\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n const handleAddLocalParticipant = () => {\n if (_propagateMaster) {\n propagateMasterFunc();\n }\n\n if (_playerInterface.isPaused === false) {\n _emitter.once('timeupdate', restartSyncLoop);\n }\n };\n\n const handleAddRemoteParticipant = () => {\n if (_propagateMaster) {\n propagateMasterFunc();\n }\n };\n\n const isConnected = () => {\n return room._isDataChannelOpen && room.isConnected;\n };\n\n const parseDataEvents = function () {\n let msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(() => {});\n }\n };\n\n const getCurrentPlayerPosition = () => {\n let position = _playerInterface.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n const getTimeDifference = (fragmentSn, fragmentPos, ping) => {\n let seekRanges = _playerInterface.buffered;\n let position = (fragmentPos + ping / 2) / 1000;\n let currentPlayerPosition = getCurrentPlayerPosition() / 1000;\n\n if (seekRanges && !_playerInterfaceOptions.ignoreBufferedTimeRanges) {\n let seekRange = {};\n\n for (let i = 0; i < seekRanges.length; i++) {\n let _c_start = seekRanges.start(i);\n\n let _c_end = seekRanges.end(i);\n\n if (!seekRange.start || _c_start < seekRange.start) {\n seekRange.start = _c_start;\n }\n\n if (!seekRange.end || _c_end > seekRange.end) {\n seekRange.end = _c_end;\n }\n }\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position: position - currentPlayerPosition,\n realPosition: position - currentPlayerPosition,\n isBufferSufficient: true\n };\n } else if (position < seekRange.start) {\n room._log(\"Syncing to \".concat(seekRange.start, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.start + 0.5 - currentPlayerPosition,\n realPosition: position - currentPlayerPosition,\n isBufferSufficient: false\n };\n } else if (position > seekRange.end) {\n room._log(\"Syncing to \".concat(seekRange.end, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.end - 0.5 - currentPlayerPosition,\n realPosition: position - currentPlayerPosition,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n isBufferSufficient: false\n };\n } else {\n return {\n position: position - currentPlayerPosition,\n realPosition: position - currentPlayerPosition,\n isBufferSufficient: true\n };\n }\n };\n\n const seekForward = () => {\n return new Promise((resolve, reject) => {\n let diff = _playerInterface.buffered.end(0) - _playerInterface.currentTime;\n\n let diff_target = diff - safeSpace;\n\n let __ = () => {\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n isSyncing = false;\n reject('Stalled');\n };\n\n console.log('Users stream is behind behind live by:', diff);\n\n if (diff_target > 0) {\n _emitter.once('stalled', __);\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(() => {\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n isSyncing = false;\n\n _emitter.off('stalled', __);\n\n resolve();\n }, diff_target * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n isSyncing = true;\n\n _playerInterface.setPlaybackRate(playbackRate);\n } else {\n resolve();\n }\n });\n };\n\n const seekBy = time => {\n return new Promise((resolve, reject) => {\n if (_playerInterface.currentTime !== time) {\n if (time > 0 && time < fastForwardThreshold && !_playerInterfaceOptions.disableFastSeek) {\n room._log(\"Fast forward to seek...\");\n\n let wasPaused = false;\n\n let _handleFailed = () => {\n if (wasPaused) {\n _playerInterface.pause();\n }\n\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n let _fastForward = () => {\n isProgrammaticallySeeked = true;\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(() => {\n _emitter.off('stalled', _handleFailed);\n\n if (wasPaused && _playerInterface.isVod) {\n _playerInterface.pause();\n }\n\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n resolve();\n }, time * 1000 / (playbackRate - 1), 20);\n\n _playerInterface.setPlaybackRate(playbackRate);\n };\n\n _emitter.once('stalled', _handleFailed);\n\n if (_playerInterface.isPaused) {\n wasPaused = true;\n\n _playerInterface.play().then(() => {\n _fastForward();\n }).catch(_handleFailed);\n } else {\n _fastForward();\n }\n } else {\n room._log(\"Jump to seek...\");\n\n let currentTimestamp = Date.now();\n let __failsafeId = null;\n\n let _resolve = () => {\n clearTimeout(__failsafeId);\n __failsafeId = null;\n isProgrammaticallySeeked = false;\n\n room._log(\"It took the player \".concat((Date.now() - currentTimestamp) / 1000, \" seconds to seek \"));\n\n resolve();\n };\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _emitter.once('playing', _resolve);\n\n __failsafeId = setTimeout(_resolve, waitForPlayingEventAfterSeek);\n\n _playerInterface.seek(_playerInterface.currentTime + time);\n }\n } else resolve();\n });\n };\n\n const seekTo = time => {\n return new Promise((resolve, reject) => {\n if (_playerInterface.currentTime !== time) {\n let diff = time - _playerInterface.currentTime;\n\n if (_playerInterface.currentTime < time && diff < fastForwardThreshold && !_playerInterfaceOptions.disableFastSeek) {\n room._log(\"Fast forward to seek...\");\n\n let wasPaused = false;\n\n let _handleFailed = () => {\n if (wasPaused) {\n _playerInterface.pause();\n }\n\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n let _fastForward = () => {\n isProgrammaticallySeeked = true;\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(() => {\n _emitter.off('stalled', _handleFailed);\n\n if (wasPaused && _playerInterface.isVod) {\n _playerInterface.pause();\n }\n\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n\n _playerInterface.setPlaybackRate(playbackRate);\n };\n\n _emitter.once('stalled', _handleFailed);\n\n if (_playerInterface.isPaused) {\n wasPaused = true;\n\n _playerInterface.play().then(() => {\n _fastForward();\n }).catch(_handleFailed);\n } else {\n _fastForward();\n }\n } else {\n room._log(\"Jump to seek...\");\n\n let currentTimestamp = Date.now();\n let __failsafeId = null;\n\n let _resolve = () => {\n clearTimeout(__failsafeId);\n __failsafeId = null;\n isProgrammaticallySeeked = false;\n\n room._log(\"It took the player \".concat((Date.now() - currentTimestamp) / 1000, \" seconds to seek \"));\n\n resolve();\n };\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _emitter.once('playing', _resolve);\n\n __failsafeId = setTimeout(_resolve, waitForPlayingEventAfterSeek);\n\n _playerInterface.seek(time);\n }\n } else resolve();\n });\n };\n\n const handlePlaying = () => {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _playerInterface.isPaused;\n isPlaying = !_playerInterface.isPaused;\n };\n\n const handlePause = () => {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPlaying = !_playerInterface.isPaused;\n };\n\n const handleBuffering = () => {\n room._log('handleBuffering');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop(true);\n clientPaused().catch(() => {});\n isPreloading = _playerInterface.isPaused;\n }\n };\n\n const roomSyncSend = slaveId => {\n var _playerInterface2;\n\n if (!_playerInterface) {\n room._log(\"I've been asked for position even if we don't have player attached.\\n Does it mean I'm the master?\");\n\n return Promise.resolve();\n }\n\n var fragmentData = ((_playerInterface2 = _playerInterface) === null || _playerInterface2 === void 0 ? void 0 : _playerInterface2.currentFragment) || {\n fragment: String(\"0\"),\n fragment_pos: Number(parseInt(getCurrentPlayerPosition()))\n };\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentData.fragment, \" # \").concat(fragmentData.fragment_pos));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId),\n ...fragmentData\n }\n });\n };\n\n const getSyncData = () => {\n var _playerInterface3;\n\n room._log('Sending roomSync request');\n\n let roomId = room.roomId;\n var fragmentData = ((_playerInterface3 = _playerInterface) === null || _playerInterface3 === void 0 ? void 0 : _playerInterface3.currentFragment) || {\n fragment: String(\"0\"),\n fragment_pos: Number(parseInt(getCurrentPlayerPosition()))\n };\n return new Promise((resolve, reject) => {\n let now = new Date().getTime();\n let ping = null;\n let sid = setTimeout(() => {\n room.off('data', fn, this);\n reject('Timeout');\n }, 3000);\n let body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n ...fragmentData\n };\n\n let fn = msg => {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, this);\n room.sendMessage(room.handleId, {\n body\n }).then(fn).catch(e => {\n room.off('data', fn, this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n const clientPaused = () => {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n const propagateMasterFunc = () => {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function () {\n let {\n playerInterface,\n propagateMaster = false\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _playerInterface = playerInterface;\n _playerInterfaceOptions = { ..._playerInterfaceOptions,\n ...(_playerInterface.syncSettings || {})\n };\n _propagateMaster = propagateMaster;\n\n room._log('Interface options passed: ', _playerInterface.syncSettings || {});\n\n room._log('All interface options: ', _playerInterfaceOptions);\n\n if (_playerInterfaceOptions.type === 'none') {\n room._log('Sync module has been disabled via type:none');\n\n return;\n } // if(_playerInterfaceOptions.type === 'push') {\n // \troom._log('Push sync is not implemented in this sync module yet');\n // \treturn;\n // }\n\n\n if (_playerInterface.isVod) {\n room._log('VOD sync is not implemented in this sync module yet');\n\n return;\n }\n\n playerInterface.addHandlers({\n handlePause: event => {\n room._log('handlePause');\n\n _emitter.emit('pause', event);\n },\n handlePlaying: event => {\n room._log('handlePlaying');\n\n _emitter.emit('playing', event);\n },\n handleBuffering: event => {\n room._log('handleBuffering');\n\n _emitter.emit('buffering', event);\n\n _emitter.emit('stalled', event);\n },\n handleTimeupdate: event => {\n room._log('handleTimeupdate');\n\n _emitter.emit('timeupdate', event);\n }\n });\n isPlaying = _playerInterface.isPaused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (_propagateMaster) {\n propagateMasterFunc().catch(() => {});\n }\n\n if (_playerInterface.isPaused === false) {\n _emitter.once('timeupdate', restartSyncLoop);\n }\n\n _emitter.on('buffering', handleBuffering);\n\n _emitter.on('playing', handlePlaying);\n\n _emitter.on('pause', handlePause);\n },\n destroy: () => {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n _playerInterface = null;\n\n _emitter.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncModule);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-module.js?");
9311
9311
 
9312
9312
  /***/ }),
9313
9313
 
@@ -9379,7 +9379,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9379
9379
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9380
9380
 
9381
9381
  "use strict";
9382
- eval("__webpack_require__.r(__webpack_exports__);\n/* WEBPACK VAR INJECTION */(function(Buffer) {/* harmony import */ var swagger_client__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! swagger-client */ \"./node_modules/swagger-client/es/index.js\");\n/* harmony import */ var _wt_config__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./wt-config */ \"./src/modules/wt-config.js\");\n/* harmony import */ var _wt_emitter__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./wt-emitter */ \"./src/modules/wt-emitter.js\");\n\n\n\n\nclass Auth {\n constructor(enableDebugFlag) {\n let language = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'en-GB';\n let storagePrefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : \"\";\n let apiUrl = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;\n this.ID_TOKEN = \"\".concat(storagePrefix !== \"\" ? storagePrefix + '_' : '', \"rwt_idToken\");\n this.ACCESS_TOKEN = \"\".concat(storagePrefix !== \"\" ? storagePrefix + '_' : '', \"rwt_accessToken\");\n this.REFRESH_TOKEN = \"\".concat(storagePrefix !== \"\" ? storagePrefix + '_' : '', \"rwt_refreshToken\");\n Object.assign(this, Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_2__[\"default\"])());\n this.__log = Auth.noop;\n\n if (enableDebugFlag) {\n this._enableDebug();\n }\n\n this.__language = language;\n this.__refreshTokenPromise = null;\n this.__isRefreshing = false;\n this.__isLogged = null;\n this.__parsedJwt = null;\n this.__specUrl = apiUrl ? apiUrl : _wt_config__WEBPACK_IMPORTED_MODULE_1__[\"default\"].apiUrl;\n this.__client = this.initialize(true);\n }\n\n static noop() {}\n\n _enableDebug() {\n this.__log = console.log.bind(console);\n }\n\n _requestInterceptor(req) {\n if (!req.headers) {\n req.headers = {};\n }\n\n req.headers['Accept-Language'] = this.__language;\n return req;\n }\n\n _responseInterceptor(res, req) {\n if (res.status === 401) {\n if (this.__isLogged) {\n let rt = localStorage.getItem(this.REFRESH_TOKEN);\n this.__refreshTokenPromise = this.__isRefreshing ? this.__refreshTokenPromise : this.__client.then(client => {\n this.__isRefreshing = true;\n return client.apis.auth.refreshToken({}, {\n requestBody: {\n refreshToken: localStorage.getItem(this.REFRESH_TOKEN)\n }\n });\n }).then(r => {\n this.__isRefreshing = false;\n return this.login(r.data.idToken, r.data.accessToken, rt, true);\n }).catch(e => {\n this.__isRefreshing = false;\n this.logout();\n return Promise.reject(e);\n });\n return this.__refreshTokenPromise.then(() => swagger_client__WEBPACK_IMPORTED_MODULE_0__[\"default\"].http({ ...req,\n headers: { ...req.headers,\n Authorization: 'Bearer ' + localStorage.getItem(this.ID_TOKEN)\n }\n })).then(res => {\n if (typeof res.obj === 'object' && res.obj !== null) {\n res.data = res.obj;\n }\n\n return res;\n });\n }\n }\n\n if (typeof res.obj === 'object' && res.obj !== null) {\n res.data = res.obj;\n }\n\n return res;\n }\n\n initialize() {\n let isInitialEvent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n let isReauth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n let idToken = localStorage.getItem(this.ID_TOKEN);\n let authorizations = {};\n\n if (idToken) {\n authorizations['bearer'] = '' + idToken;\n }\n\n this.__isLogged = !!idToken;\n\n let _that = this;\n\n return new swagger_client__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this.__specUrl, {\n authorizations,\n requestInterceptor: this._requestInterceptor.bind(this),\n responseInterceptor: function (res) {\n return _that._responseInterceptor(res, this);\n }\n }).then(client => {\n this.__isLogged = !!idToken;\n this.__parsedJwt = this.parseJwt(idToken);\n this.emit(this.__isLogged ? 'login' : 'logout', {\n client,\n isInitialEvent,\n isLoggedInAsDevice: this.isLoggedInAs(this.__parsedJwt, 'device'),\n isLoggedInAsObserver: this.isLoggedInAs(this.__parsedJwt, 'observer'),\n isLoggedInAsInstanceAdmin: this.isLoggedInAs(this.__parsedJwt, 'instanceAdmin'),\n isLoggedInAsAdmin: this.isLoggedInAs(this.__parsedJwt, 'admin'),\n domain: this.getDomain(this.__parsedJwt),\n isReauth\n });\n return client;\n }).catch(e => {\n this.__isLogged = false;\n this.emit('logout', {\n client: null,\n isInitialEvent,\n isLoggedInAsDevice: false,\n isLoggedInAsObserver: false,\n isLoggedInAsInstanceAdmin: false,\n isLoggedInAsAdmin: false,\n isReauth\n });\n return Promise.reject(e);\n });\n }\n\n login(idToken, accessToken, refreshToken) {\n let isReauth = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n localStorage.setItem(this.ID_TOKEN, idToken);\n localStorage.setItem(this.ACCESS_TOKEN, accessToken);\n localStorage.setItem(this.REFRESH_TOKEN, refreshToken);\n return this.__client = this.initialize(false, isReauth);\n }\n\n logout() {\n localStorage.removeItem(this.ID_TOKEN);\n localStorage.removeItem(this.ACCESS_TOKEN);\n localStorage.removeItem(this.REFRESH_TOKEN);\n return this.__client = this.initialize();\n }\n\n isLoggedIn() {\n return this.__isLogged;\n }\n\n isLoggedInAs(parsedJwt) {\n let as = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'device';\n parsedJwt = parsedJwt || this.__parsedJwt;\n return !!(parsedJwt && parsedJwt['cognito:groups'] && parsedJwt['cognito:groups'].includes(as));\n }\n\n setLanguage(language) {\n this.__language = language;\n return this.__language;\n }\n\n getDomain(parsedJwt) {\n parsedJwt = parsedJwt || this.__parsedJwt;\n return parsedJwt['custom:domain'];\n }\n\n parseJwt(jwt) {\n if (!jwt || typeof jwt !== \"string\") return false;\n let match = jwt.match(/^(([0-9a-zA-Z]*)\\.){2}[\\w-]*$/);\n if (!match || !match[2]) return false;\n\n try {\n match = new Buffer(match[2], 'base64').toString('binary');\n return JSON.parse(match);\n } catch (e) {\n return false;\n }\n }\n\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Auth);\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../node_modules/node-libs-browser/node_modules/buffer/index.js */ \"./node_modules/node-libs-browser/node_modules/buffer/index.js\").Buffer))\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-auth.js?");
9382
+ eval("__webpack_require__.r(__webpack_exports__);\n/* WEBPACK VAR INJECTION */(function(Buffer) {/* harmony import */ var swagger_client__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! swagger-client */ \"./node_modules/swagger-client/es/index.js\");\n/* harmony import */ var _wt_config__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./wt-config */ \"./src/modules/wt-config.js\");\n/* harmony import */ var _wt_emitter__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./wt-emitter */ \"./src/modules/wt-emitter.js\");\n\n\n\n\nclass Auth {\n constructor(enableDebugFlag) {\n let language = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'en-GB';\n let storagePrefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : \"\";\n let apiUrl = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;\n this.ID_TOKEN = \"\".concat(storagePrefix !== \"\" ? storagePrefix + '_' : '', \"rwt_idToken\");\n this.ACCESS_TOKEN = \"\".concat(storagePrefix !== \"\" ? storagePrefix + '_' : '', \"rwt_accessToken\");\n this.REFRESH_TOKEN = \"\".concat(storagePrefix !== \"\" ? storagePrefix + '_' : '', \"rwt_refreshToken\");\n Object.assign(this, Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_2__[\"default\"])());\n this.__log = Auth.noop;\n\n if (enableDebugFlag) {\n this._enableDebug();\n }\n\n this.__language = language;\n this.__refreshTokenPromise = null;\n this.__isRefreshing = false;\n this.__isLogged = null;\n this.__parsedJwt = null;\n this.__specUrl = apiUrl ? apiUrl : _wt_config__WEBPACK_IMPORTED_MODULE_1__[\"default\"].apiUrl;\n this.__client = this.initialize(true);\n }\n\n static noop() {}\n\n _enableDebug() {\n this.__log = console.log.bind(console);\n }\n\n _requestInterceptor(req) {\n if (!req.headers) {\n req.headers = {};\n }\n\n req.headers['Accept-Language'] = this.__language;\n return req;\n }\n\n _responseInterceptor(res, req) {\n if (res.status === 401) {\n if (this.__isLogged) {\n let rt = localStorage.getItem(this.REFRESH_TOKEN);\n this.__refreshTokenPromise = this.__isRefreshing ? this.__refreshTokenPromise : this.__client.then(client => {\n this.__isRefreshing = true;\n return client.apis.auth.refreshToken({}, {\n requestBody: {\n refreshToken: localStorage.getItem(this.REFRESH_TOKEN)\n }\n });\n }).then(r => {\n this.__isRefreshing = false;\n return this.login(r.data.idToken, r.data.accessToken, rt, true);\n }).catch(e => {\n this.__isRefreshing = false;\n this.logout();\n return Promise.reject(e);\n });\n return this.__refreshTokenPromise.then(() => swagger_client__WEBPACK_IMPORTED_MODULE_0__[\"default\"].http({ ...req,\n headers: { ...req.headers,\n Authorization: 'Bearer ' + localStorage.getItem(this.ID_TOKEN)\n }\n })).then(res => {\n if (typeof res.obj === 'object' && res.obj !== null) {\n res.data = res.obj;\n }\n\n return res;\n });\n }\n }\n\n if (typeof res.obj === 'object' && res.obj !== null) {\n res.data = res.obj;\n }\n\n return res;\n }\n\n initialize() {\n let isInitialEvent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n let isReauth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n let idToken = localStorage.getItem(this.ID_TOKEN);\n let authorizations = {};\n\n if (idToken) {\n authorizations['bearer'] = '' + idToken;\n }\n\n this.__isLogged = !!idToken;\n\n let _that = this;\n\n return new swagger_client__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this.__specUrl, {\n authorizations,\n requestInterceptor: this._requestInterceptor.bind(this),\n responseInterceptor: function (res) {\n return _that._responseInterceptor(res, this);\n }\n }).then(client => {\n this.__isLogged = !!idToken;\n this.__parsedJwt = this.parseJwt(idToken);\n this.emit(this.__isLogged ? 'login' : 'logout', {\n client,\n isInitialEvent,\n isReauth,\n isLoggedInAsDevice: this.isLoggedInAs(this.__parsedJwt, 'device'),\n isLoggedInAsObserver: this.isLoggedInAs(this.__parsedJwt, 'observer'),\n isLoggedInAsInstanceAdmin: this.isLoggedInAs(this.__parsedJwt, 'instanceAdmin'),\n isLoggedInAsAdmin: this.isLoggedInAs(this.__parsedJwt, 'admin'),\n domain: this.getDomain(this.__parsedJwt)\n });\n return client;\n }).catch(e => {\n this.__isLogged = false;\n this.emit('logout', {\n client: null,\n isInitialEvent,\n isLoggedInAsDevice: false,\n isLoggedInAsObserver: false,\n isLoggedInAsInstanceAdmin: false,\n isLoggedInAsAdmin: false,\n isReauth\n });\n return Promise.reject(e);\n });\n }\n\n login(idToken, accessToken, refreshToken) {\n let isReauth = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n localStorage.setItem(this.ID_TOKEN, idToken);\n localStorage.setItem(this.ACCESS_TOKEN, accessToken);\n localStorage.setItem(this.REFRESH_TOKEN, refreshToken);\n return this.__client = this.initialize(false, isReauth);\n }\n\n logout() {\n localStorage.removeItem(this.ID_TOKEN);\n localStorage.removeItem(this.ACCESS_TOKEN);\n localStorage.removeItem(this.REFRESH_TOKEN);\n return this.__client = this.initialize();\n }\n\n isLoggedIn() {\n return this.__isLogged;\n }\n\n isLoggedInAs(parsedJwt) {\n let as = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'device';\n parsedJwt = parsedJwt || this.__parsedJwt;\n return !!(parsedJwt && parsedJwt['cognito:groups'] && parsedJwt['cognito:groups'].includes(as));\n }\n\n setLanguage(language) {\n this.__language = language;\n return this.__language;\n }\n\n getDomain(parsedJwt) {\n parsedJwt = parsedJwt || this.__parsedJwt;\n return parsedJwt['custom:domain'];\n }\n\n parseJwt(jwt) {\n if (!jwt || typeof jwt !== \"string\") return false;\n let match = jwt.match(/^(([0-9a-zA-Z]*)\\.){2}[\\w-]*$/);\n if (!match || !match[2]) return false;\n\n try {\n match = new Buffer(match[2], 'base64').toString('binary');\n return JSON.parse(match);\n } catch (e) {\n return false;\n }\n }\n\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Auth);\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../node_modules/node-libs-browser/node_modules/buffer/index.js */ \"./node_modules/node-libs-browser/node_modules/buffer/index.js\").Buffer))\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-auth.js?");
9383
9383
 
9384
9384
  /***/ }),
9385
9385
 
@@ -9427,7 +9427,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var aws_
9427
9427
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9428
9428
 
9429
9429
  "use strict";
9430
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! webrtc-adapter */ \"./node_modules/webrtc-adapter/src/js/adapter_core.js\");\n/* harmony import */ var _wt_emitter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./wt-emitter */ \"./src/modules/wt-emitter.js\");\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./wt-utils */ \"./src/modules/wt-utils.js\");\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n// Watch together janus webrtc library\n\n\n\n\nclass Room {\n constructor(debug) {\n this.debug = debug;\n this.sessions = [];\n this.safariVp8 = false;\n this.browser = webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser;\n this.browserDetails = webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails;\n this.webrtcSupported = Room.isWebrtcSupported();\n this.safariVp8TestPromise = Room.testSafariVp8();\n this.safariVp8 = null;\n this.safariVp8TestPromise.then(safariVp8 => {\n this.safariVp8 = safariVp8;\n }); // Let's get it started\n\n this.whenInitialized = this.initialize();\n }\n\n initialize() {\n return this.safariVp8TestPromise.then(() => this);\n }\n\n createSession() {\n let constructId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'reactooroom';\n let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n return new RoomSession(constructId, type, {\n debug: this.debug,\n ...options\n });\n }\n\n static testSafariVp8() {\n return new Promise(resolve => {\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'safari' && webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.version >= 605) {\n if (RTCRtpSender && RTCRtpSender.getCapabilities && RTCRtpSender.getCapabilities(\"video\") && RTCRtpSender.getCapabilities(\"video\").codecs && RTCRtpSender.getCapabilities(\"video\").codecs.length) {\n var isVp8 = false;\n\n for (var i in RTCRtpSender.getCapabilities(\"video\").codecs) {\n var codec = RTCRtpSender.getCapabilities(\"video\").codecs[i];\n\n if (codec && codec.mimeType && codec.mimeType.toLowerCase() === \"video/vp8\") {\n isVp8 = true;\n break;\n }\n }\n\n resolve(isVp8);\n } else {\n // We do it in a very ugly way, as there's no alternative...\n // We create a PeerConnection to see if VP8 is in an offer\n var testpc = new RTCPeerConnection({}, {});\n testpc.createOffer({\n offerToReceiveVideo: true\n }).then(function (offer) {\n let result = offer.sdp.indexOf(\"VP8\") !== -1;\n testpc.close();\n testpc = null;\n resolve(result);\n });\n }\n } else resolve(false);\n });\n }\n\n static isWebrtcSupported() {\n return window.RTCPeerConnection !== undefined && window.RTCPeerConnection !== null && navigator.mediaDevices !== undefined && navigator.mediaDevices !== null && navigator.mediaDevices.getUserMedia !== undefined && navigator.mediaDevices.getUserMedia !== null;\n }\n\n}\n\nclass RoomSession {\n static noop() {}\n\n static randomString(len) {\n var charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n var randomString = '';\n\n for (var i = 0; i < len; i++) {\n var randomPoz = Math.floor(Math.random() * charSet.length);\n randomString += charSet.substring(randomPoz, randomPoz + 1);\n }\n\n return randomString;\n } //TODO: solve\n // #eventList = ['error', 'kicked', 'addLocalParticipant', ,'addRemoteInstructor','addRemoteParticipant','addRemoteTalkback', 'addRemoteObserver', 'removeRemoteInstructor', 'removeLocalParticipant', 'removeRemoteParticipant', 'removeRemoteTalkback', 'removeRemoteObserver', 'localMuted', 'localHasVideo', 'localHasAudio', 'data', 'iceState', 'connectionState', 'joined', 'joining', 'dataChannel', 'disconnect', 'observerIds', 'talkbackIds', 'instructorId', 'published', 'publishing', 'remoteTrackMuted', 'streamingStatus', 'streaming', 'streamStarting'];\n //\n\n\n constructor() {\n let constructId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'reactooroom';\n let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n Object.assign(this, Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])());\n this.defaultDataChannelLabel = 'JanusDataChannel';\n this.server = null;\n this.iceServers = null;\n this.token = null;\n this.roomId = null;\n this.streamId = null;\n this.pin = null;\n this.userId = null;\n this.sessiontype = type;\n this.initialBitrate = 0;\n this.recordingFilename = null;\n this.pluginName = RoomSession.sessionTypes[type];\n this.options = options;\n this.id = null;\n this.privateId = null;\n this.constructId = constructId || RoomSession.randomString(16);\n this.sessionId = null;\n this.handleId = null;\n this.ws = null;\n this.isRestarting = false;\n this.isConnecting = false;\n this.isDisconnecting = false;\n this.isConnected = false;\n this.isPublished = false;\n this.isReclaiming = false;\n this.isStreaming = false;\n this._ipv6Support = false;\n this._retries = 0;\n this._maxRetries = 3;\n this._keepAliveId = null;\n this._participants = [];\n this._roomType = 'watchparty';\n this._isDataChannelOpen = false;\n this._abortController = null;\n this.isAudioMuted = false;\n this.isVideoMuted = false;\n this.isVideoEnabled = false;\n this.isAudioEnabed = false;\n this.isUnifiedPlan = RoomSession.checkUnifiedPlan();\n this.subscriptionRules = { ...RoomSession.subscriptionRules,\n ...(this.options.subscriptionRules || {})\n };\n this._log = RoomSession.noop;\n\n if (this.options.debug) {\n this._enableDebug();\n }\n } // Check if this browser supports Unified Plan and transceivers\n // Based on https://codepen.io/anon/pen/ZqLwWV?editors=0010\n\n\n static checkUnifiedPlan() {\n let unifiedPlan = false;\n\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'firefox' && webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.version >= 59) {\n // Firefox definitely does, starting from version 59\n unifiedPlan = true;\n } else if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'chrome' && webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.version >= 72) {\n // Chrome does, but it's only usable from version 72 on\n unifiedPlan = true;\n } else if (!window.RTCRtpTransceiver || !('currentDirection' in RTCRtpTransceiver.prototype)) {\n // Safari supports addTransceiver() but not Unified Plan when\n // currentDirection is not defined (see codepen above).\n unifiedPlan = false;\n } else {\n // Check if addTransceiver() throws an exception\n const tempPc = new RTCPeerConnection();\n\n try {\n tempPc.addTransceiver('audio');\n unifiedPlan = true;\n } catch (e) {}\n\n tempPc.close();\n }\n\n return unifiedPlan;\n }\n\n _participantShouldSubscribe(userId) {\n const myUser = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(this.display);\n const remoteUser = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(userId);\n let localUserRole = (myUser === null || myUser === void 0 ? void 0 : myUser.role) || 'participant';\n let remoteUserRole = (remoteUser === null || remoteUser === void 0 ? void 0 : remoteUser.role) || 'participant';\n return this.subscriptionRules[localUserRole][this._roomType || 'watchparty'].indexOf(remoteUserRole) > -1;\n }\n\n _getAddParticipantEventName(handleId) {\n var _decodeJanusDisplay;\n\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n this.emit('error', {\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'getParticipantEventName']\n });\n }\n\n const participantRole = (_decodeJanusDisplay = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay === void 0 ? void 0 : _decodeJanusDisplay.role;\n\n switch (participantRole) {\n case 'participant':\n return 'addRemoteParticipant';\n\n case 'talkback':\n return 'addRemoteTalkback';\n\n case 'monitor':\n return 'addRemoteTalkback';\n\n case 'observer':\n case 'observerSolo1':\n case 'observerSolo2':\n case 'observerSolo3':\n return 'addRemoteObserver';\n\n case 'host':\n return 'addRemoteInstructor';\n\n case 'companionTV':\n return 'addRemoteCompanionTV';\n\n case 'companionPhone':\n return 'addRemoteCompanionPhone';\n\n default:\n return 'addRemoteParticipant';\n }\n }\n\n _getRemoveParticipantEventName(handleId) {\n var _decodeJanusDisplay2;\n\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n this.emit('error', {\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'getParticipantEventName']\n });\n }\n\n const participantRole = (_decodeJanusDisplay2 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay2 === void 0 ? void 0 : _decodeJanusDisplay2.role;\n\n switch (participantRole) {\n case 'participant':\n return 'removeRemoteParticipant';\n\n case 'talkback':\n return 'removeRemoteTalkback';\n\n case 'monitor':\n return 'removeRemoteTalkback';\n\n case 'observer':\n case 'observerSolo1':\n case 'observerSolo2':\n case 'observerSolo3':\n return 'removeRemoteObserver';\n\n case 'host':\n return 'removeRemoteInstructor';\n\n case 'companionTV':\n return 'removeRemoteCompanionTV';\n\n case 'companionPhone':\n return 'removeRemoteCompanionPhone';\n\n default:\n return 'removeRemoteParticipant';\n }\n }\n\n sendMessage(handleId) {\n let message = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n body: 'Example Body'\n };\n let dontWait = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n let dontResolveOnAck = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n return this._send({\n \"janus\": \"message\",\n \"handle_id\": handleId,\n ...message\n }, dontWait, dontResolveOnAck).then(json => {\n if (json && json[\"janus\"] === \"success\") {\n let plugindata = json[\"plugindata\"] || {};\n let data = plugindata[\"data\"];\n return Promise.resolve(data);\n }\n\n return Promise.resolve();\n }).catch(json => {\n if (json && json[\"error\"]) {\n return Promise.reject({\n type: 'warning',\n id: 1,\n message: 'sendMessage failed',\n data: json[\"error\"]\n });\n } else {\n return Promise.reject({\n type: 'warning',\n id: 1,\n message: 'sendMessage failed',\n data: json\n });\n }\n });\n }\n\n _send() {\n let request = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let ignoreResponse = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n let dontResolveOnAck = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n let transaction = RoomSession.randomString(12);\n let requestData = { ...request,\n transaction,\n token: this.token,\n ...(this.sessionId && {\n 'session_id': this.sessionId\n } || {})\n };\n\n this._log(requestData);\n\n return new Promise((resolve, reject) => {\n let messageTimeoutId = null;\n\n let abortResponse = () => {\n this._abortController.signal.removeEventListener('abort', abortResponse);\n\n clearTimeout(messageTimeoutId);\n this.ws.removeEventListener('message', parseResponse);\n reject({\n type: 'warning',\n id: 17,\n message: 'connection cancelled'\n });\n };\n\n let parseResponse = event => {\n let json = JSON.parse(event.data);\n let r_transaction = json['transaction'];\n\n if (r_transaction === transaction && (!dontResolveOnAck || json['janus'] !== 'ack')) {\n clearTimeout(messageTimeoutId);\n\n this._abortController.signal.removeEventListener('abort', abortResponse);\n\n this.ws.removeEventListener('message', parseResponse);\n\n if (json['janus'] === 'error') {\n var _json$error;\n\n if ((json === null || json === void 0 ? void 0 : (_json$error = json.error) === null || _json$error === void 0 ? void 0 : _json$error.code) == 403) {\n this.disconnect(true);\n }\n\n reject({\n type: 'error',\n id: 2,\n message: 'send failed',\n data: json,\n requestData\n });\n } else {\n resolve(json);\n }\n }\n };\n\n if (ignoreResponse) {\n if (this.ws && this.ws.readyState === 1) {\n this.ws.send(JSON.stringify(requestData));\n }\n\n resolve();\n } else {\n if (this.ws && this.ws.readyState === 1) {\n this.ws.addEventListener('message', parseResponse);\n messageTimeoutId = setTimeout(() => {\n this.ws.removeEventListener('message', parseResponse);\n\n this._abortController.signal.removeEventListener('abort', abortResponse);\n\n reject({\n type: 'error',\n id: 3,\n message: 'send timeout',\n data: requestData\n });\n }, 10000);\n\n this._abortController.signal.addEventListener('abort', abortResponse);\n\n this.ws.send(JSON.stringify(requestData));\n } else {\n reject({\n type: 'warning',\n id: 29,\n message: 'No connection to WebSockets',\n data: requestData\n });\n }\n }\n });\n }\n\n _connectionClosed() {\n if (!this.isConnected || this.isConnecting || this.isDisconnecting) {\n return;\n }\n\n if (this._retries < this._maxRetries) {\n setTimeout(() => {\n this._retries++;\n\n this._reconnect().catch(e => {\n this.emit('error', e);\n });\n }, 3000 * this._retries);\n } else {\n if (this.sessiontype === 'reactooroom') {\n this.disconnect(true);\n } else if (this.sessiontype === 'streaming') {\n this.stopStream();\n }\n\n this.emit('error', {\n type: 'error',\n id: 4,\n message: 'Lost connection to WebSockets',\n data: null\n });\n }\n }\n\n _wipeListeners() {\n if (this.ws) {\n this.ws.removeEventListener('close', this.__connectionClosedBoundFn);\n this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);\n }\n }\n\n _startKeepAlive() {\n this._send({\n \"janus\": \"keepalive\"\n }).then(json => {\n if (json[\"janus\"] !== 'ack') {\n this.emit('error', {\n type: 'warning',\n id: 5,\n message: 'keepalive response suspicious',\n data: json[\"janus\"]\n });\n }\n }).catch(e => {\n this.emit('error', {\n type: 'warning',\n id: 6,\n message: 'keepalive dead',\n data: e\n });\n\n this._connectionClosed();\n });\n\n this._keepAliveId = setTimeout(() => {\n this._startKeepAlive();\n }, 30000);\n }\n\n _stopKeepAlive() {\n clearTimeout(this._keepAliveId);\n }\n\n _handleWsEvents(event) {\n let json = JSON.parse(event.data);\n var sender = json[\"sender\"];\n var type = json[\"janus\"];\n\n let handle = this._getHandle(sender);\n\n if (!handle) {\n return;\n }\n\n if (type === \"trickle\") {\n let candidate = json[\"candidate\"];\n let config = handle.webrtcStuff;\n\n if (config.pc && config.remoteSdp) {\n if (!candidate || candidate.completed === true) {\n config.pc.addIceCandidate(null);\n } else {\n config.pc.addIceCandidate(candidate);\n }\n } else {\n if (!config.candidates) {\n config.candidates = [];\n }\n\n config.candidates.push(candidate);\n }\n } else if (type === \"webrtcup\") {//none universal\n } else if (type === \"hangup\") {\n this._log('hangup on', handle.handleId);\n\n this._removeParticipant(handle.handleId, null, false);\n } else if (type === \"detached\") {\n this._log('detached on', handle.handleId);\n\n this._removeParticipant(handle.handleId, null, true);\n } else if (type === \"media\") {\n this._log('Media event:', handle.handleId, json[\"type\"], json[\"receiving\"], json[\"mid\"]);\n } else if (type === \"slowlink\") {\n this._log('Slowlink', handle.handleId, json[\"uplink\"], json[\"lost\"], json[\"mid\"]);\n } else if (type === \"event\") {//none universal\n } else if (type === 'timeout') {\n this.ws.close(3504, \"Gateway timeout\");\n } else if (type === 'success' || type === 'error') {// we're capturing those elsewhere\n } else {\n this._log(\"Unknown event: \".concat(type, \" on session: \").concat(this.sessionId));\n } // LOCAL\n\n\n if (sender === this.handleId) {\n if (type === \"event\") {\n var plugindata = json[\"plugindata\"] || {};\n var msg = plugindata[\"data\"] || {};\n var jsep = json[\"jsep\"];\n let result = msg[\"result\"] || null;\n let event = msg[\"videoroom\"] || null;\n let list = msg[\"publishers\"] || {};\n let leaving = msg[\"leaving\"]; //let joining = msg[\"joining\"];\n\n let unpublished = msg[\"unpublished\"];\n let error = msg[\"error\"];\n\n if (event === \"joined\") {\n this.id = msg[\"id\"];\n this.privateId = msg[\"private_id\"];\n this.isConnected = true;\n this.emit('joined', true);\n\n this._log('We have successfully joined Room');\n\n for (let f in list) {\n let userId = list[f][\"display\"];\n let streams = list[f][\"streams\"] || [];\n let id = list[f][\"id\"];\n\n for (let i in streams) {\n streams[i][\"id\"] = id;\n streams[i][\"display\"] = userId;\n }\n\n this._log('Remote userId: ', userId);\n\n if (this._participantShouldSubscribe(userId)) {\n this._log('Creating user: ', userId);\n\n this._createParticipant(userId, id).then(handle => {\n return this.sendMessage(handle.handleId, {\n body: {\n \"request\": \"join\",\n \"room\": this.roomId,\n \"ptype\": \"subscriber\",\n \"feed\": id,\n \"private_id\": this.privateId,\n ...(this.webrtcVersion > 1000 ? {\n id: this.userId\n } : {}),\n pin: this.pin\n }\n });\n }).catch(err => {\n this.emit('error', err);\n });\n }\n }\n } else if (event === \"event\") {\n if (msg[\"streams\"] !== undefined && msg[\"streams\"] !== null) {\n this._log('Got my own streams back', msg[\"streams\"]);\n }\n\n for (let f in list) {\n let userId = list[f][\"display\"];\n let streams = list[f][\"streams\"] || [];\n let id = list[f][\"id\"];\n\n for (let i in streams) {\n streams[i][\"id\"] = id;\n streams[i][\"display\"] = userId;\n }\n\n this._log('Remote userId: ', userId);\n\n if (this._participantShouldSubscribe(userId)) {\n this._log('Creating user: ', userId);\n\n this._createParticipant(userId, id).then(handle => {\n return this.sendMessage(handle.handleId, {\n body: {\n \"request\": \"join\",\n \"room\": this.roomId,\n \"ptype\": \"subscriber\",\n \"feed\": id,\n \"private_id\": this.privateId,\n ...(this.webrtcVersion > 1000 ? {\n id: this.userId\n } : {}),\n pin: this.pin\n }\n });\n }).catch(err => {\n this.emit('error', err);\n });\n }\n }\n\n if (leaving === 'ok') {\n this._log('leaving', this.handleId, 'this is us');\n\n this._removeParticipant(this.handleId);\n\n if (msg['reason'] === 'kicked') {\n this.emit('kicked');\n this.disconnect().catch(() => {});\n }\n } else if (leaving) {\n this._log('leaving', leaving);\n\n this._removeParticipant(null, leaving);\n }\n\n if (unpublished === 'ok') {\n this._log('unpublished', this.handleId, 'this is us');\n\n this._removeParticipant(this.handleId, null, false); // we do just hangup\n\n } else if (unpublished) {\n this._log('unpublished', unpublished);\n\n this._removeParticipant(null, unpublished, true); // we do hangup and detach\n\n }\n\n if (error) {\n this.emit('error', {\n type: 'error',\n id: 7,\n message: 'local participant error',\n data: [sender, msg]\n });\n }\n } // Streaming related\n else if (result && result[\"status\"]) {\n this.emit('streamingStatus', result[\"status\"]);\n\n if (result[\"status\"] === 'stopped') {\n this.stopStream();\n }\n\n if (result[\"status\"] === 'started') {\n this.emit('streaming', true);\n this.isStreaming = true;\n }\n }\n\n if (jsep !== undefined && jsep !== null) {\n if (this.sessiontype === 'reactooroom') {\n this._webrtcPeer(this.handleId, jsep).catch(err => {\n this.emit('error', err);\n });\n } else if (this.sessiontype === 'streaming') {\n this._publishRemote(this.handleId, jsep).catch(err => {\n this.emit('error', err);\n });\n }\n }\n } else if (type === \"webrtcup\") {\n this._log('Configuring bitrate: ' + this.initialBitrate);\n\n if (this.initialBitrate > 0) {\n this.sendMessage(this.handleId, {\n \"body\": {\n \"request\": \"configure\",\n \"bitrate\": this.initialBitrate\n }\n }).catch(() => null);\n }\n }\n } //REMOTE\n else {\n let plugindata = json[\"plugindata\"] || {};\n let msg = plugindata[\"data\"] || {};\n let jsep = json[\"jsep\"];\n let event = msg[\"videoroom\"];\n let error = msg[\"error\"];\n\n if (event === \"attached\") {\n var _decodeJanusDisplay3, _decodeJanusDisplay4;\n\n this._log('Remote have successfully joined Room', msg);\n\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: (_decodeJanusDisplay3 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay3 === void 0 ? void 0 : _decodeJanusDisplay3.userId,\n role: (_decodeJanusDisplay4 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay4 === void 0 ? void 0 : _decodeJanusDisplay4.role,\n stream: null,\n track: null,\n adding: false,\n constructId: this.constructId,\n metaData: this.options.metaData,\n hasAudioTrack: false,\n hasVideoTrack: false\n });\n }\n\n if (error) {\n this.emit('error', {\n type: 'warning',\n id: 8,\n message: 'remote participant error',\n data: [sender, msg]\n });\n }\n\n if (jsep) {\n this._publishRemote(handle.handleId, jsep).catch(err => {\n this.emit('error', err);\n });\n }\n }\n }\n\n _handleDataEvents(handleId, type, data) {\n let handle = this._getHandle(handleId);\n\n if (type === 'state') {\n this._log(\" - Data channel status - \", \"UID: \".concat(handleId), \"STATUS: \".concat(JSON.stringify(data)), \"ME: \".concat(handleId === this.handleId));\n\n if (handle) {\n let config = handle.webrtcStuff;\n config.dataChannelOpen = this.defaultDataChannelLabel === (data === null || data === void 0 ? void 0 : data.label) && (data === null || data === void 0 ? void 0 : data.state) === 'open';\n }\n\n if (handleId === this.handleId && this.defaultDataChannelLabel === (data === null || data === void 0 ? void 0 : data.label)) {\n this._isDataChannelOpen = (data === null || data === void 0 ? void 0 : data.state) === 'open';\n this.emit('dataChannel', (data === null || data === void 0 ? void 0 : data.state) === 'open');\n }\n }\n\n if (type === 'error') {\n this.emit('error', {\n type: 'warning',\n id: 9,\n message: 'data event warning',\n data: [handleId, data]\n });\n\n if (handle) {\n let config = handle.webrtcStuff;\n\n if (this.defaultDataChannelLabel === data.label) {\n config.dataChannelOpen = false;\n }\n }\n\n if (handleId === this.handleId && this.defaultDataChannelLabel === data.label) {\n this._isDataChannelOpen = false;\n this.emit('dataChannel', false);\n }\n }\n\n if (handleId === this.handleId && type === 'message') {\n let d = null;\n\n try {\n d = JSON.parse(data);\n } catch (e) {\n this.emit('error', {\n type: 'warning',\n id: 10,\n message: 'data message parse error',\n data: [handleId, e]\n });\n return;\n }\n\n this.emit('data', d);\n }\n } //removeHandle === true -> hangup, detach, removeHandle === false -> hangup\n\n\n _removeParticipant(handleId, rfid) {\n let removeHandle = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n\n let handle = this._getHandle(handleId, rfid);\n\n if (!handle) {\n return Promise.resolve();\n } else {\n handleId = handle.handleId;\n }\n\n return this._send({\n \"janus\": \"hangup\",\n \"handle_id\": handleId\n }, true).then(() => removeHandle ? this._send({\n \"janus\": \"detach\",\n \"handle_id\": handleId\n }, true) : Promise.resolve()).finally(() => {\n try {\n if (handle.webrtcStuff.stream && !this.isRestarting) {\n handle.webrtcStuff.stream.getTracks().forEach(track => track.stop());\n }\n } catch (e) {// Do nothing\n }\n\n handle.webrtcStuff.stream = null;\n\n if (handle.webrtcStuff.dataChannel) {\n Object.keys(handle.webrtcStuff.dataChannel).forEach(label => {\n handle.webrtcStuff.dataChannel[label].onmessage = null;\n handle.webrtcStuff.dataChannel[label].onopen = null;\n handle.webrtcStuff.dataChannel[label].onclose = null;\n handle.webrtcStuff.dataChannel[label].onerror = null;\n });\n }\n\n if (handle.webrtcStuff.pc) {\n handle.webrtcStuff.pc.onicecandidate = null;\n handle.webrtcStuff.pc.ontrack = null;\n handle.webrtcStuff.pc.ondatachannel = null;\n handle.webrtcStuff.pc.onconnectionstatechange = null;\n handle.webrtcStuff.pc.oniceconnectionstatechange = null;\n }\n\n try {\n handle.webrtcStuff.pc.close();\n } catch (e) {}\n\n handle.webrtcStuff = {\n stream: null,\n mySdp: null,\n mediaConstraints: null,\n pc: null,\n dataChannelOpen: false,\n dataChannel: null,\n dtmfSender: null,\n trickle: true,\n iceDone: false\n };\n\n if (handleId === this.handleId) {\n var _decodeJanusDisplay5, _decodeJanusDisplay6;\n\n this._isDataChannelOpen = false;\n this.isPublished = false;\n this.emit('published', {\n status: false,\n hasStream: false\n });\n this.emit('removeLocalParticipant', {\n id: handleId,\n userId: (_decodeJanusDisplay5 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay5 === void 0 ? void 0 : _decodeJanusDisplay5.userId,\n role: (_decodeJanusDisplay6 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay6 === void 0 ? void 0 : _decodeJanusDisplay6.role\n });\n } else {\n var _decodeJanusDisplay7, _decodeJanusDisplay8;\n\n this.emit(this._getRemoveParticipantEventName(handleId), {\n id: handleId,\n userId: (_decodeJanusDisplay7 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay7 === void 0 ? void 0 : _decodeJanusDisplay7.userId,\n role: (_decodeJanusDisplay8 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay8 === void 0 ? void 0 : _decodeJanusDisplay8.role\n });\n }\n\n if (removeHandle) {\n let handleIndex = this._participants.findIndex(p => p.handleId === handleId);\n\n this._participants.splice(handleIndex, 1);\n }\n\n return true;\n });\n }\n\n _createParticipant() {\n let userId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let rfid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n return this._send({\n \"janus\": \"attach\",\n \"plugin\": this.pluginName\n }).then(json => {\n let handleId = json.data[\"id\"];\n let handle = {\n handleId,\n rfid,\n userId,\n webrtcStuff: {\n stream: null,\n mySdp: null,\n mediaConstraints: null,\n pc: null,\n dataChannelOpen: false,\n dataChannel: null,\n dtmfSender: null,\n trickle: true,\n iceDone: false,\n isIceRestarting: false\n }\n };\n\n this._participants.push(handle);\n\n return handle;\n });\n }\n\n _joinRoom(roomId, pin, userId, display) {\n return this.sendMessage(this.handleId, {\n body: {\n \"request\": \"join\",\n \"room\": roomId,\n \"pin\": pin,\n \"ptype\": \"publisher\",\n \"display\": display,\n ...(this.webrtcVersion > 1000 ? {\n id: userId\n } : {})\n }\n }, false, true);\n }\n\n _watchStream(id) {\n return this.sendMessage(this.handleId, {\n body: {\n \"request\": \"watch\",\n id: parseInt(id)\n }\n }, false, true);\n }\n\n _leaveRoom() {\n let dontWait = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n return this.isConnected ? this.sendMessage(this.handleId, {\n body: {\n \"request\": \"leave\"\n }\n }, dontWait).finally(() => {\n this.isConnected = false;\n this.emit('joined', false);\n }) : Promise.resolve();\n } // internal reconnect\n\n\n _reconnect() {\n if (this.isReclaiming) {\n return Promise.resolve();\n }\n\n if (this.ws) {\n this._wipeListeners();\n\n if (this.ws.readyState === 1) {\n this.ws.close();\n }\n }\n\n this._stopKeepAlive();\n\n this.isReclaiming = true;\n this.emit('joining', true);\n return new Promise((resolve, reject) => {\n let abortReconnect = () => {\n this._abortController.signal.removeEventListener('abort', abortReconnect);\n\n this.ws.removeEventListener('close', this.__connectionClosedBoundFn);\n this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);\n this.ws.onopen = null;\n this.ws.onerror = null;\n this.isReclaiming = false;\n this.emit('joining', false);\n reject({\n type: 'warning',\n id: 17,\n message: 'Connection cancelled',\n data: e\n });\n };\n\n this.ws = new WebSocket(this.server, 'janus-protocol');\n this.__connectionClosedBoundFn = this._connectionClosed.bind(this);\n this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);\n this.ws.addEventListener('close', this.__connectionClosedBoundFn);\n this.ws.addEventListener('message', this.__handleWsEventsBoundFn);\n\n this.ws.onopen = () => {\n this._abortController.signal.removeEventListener('abort', abortReconnect);\n\n this._send({\n \"janus\": \"claim\"\n }).then(json => {\n this.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n this._startKeepAlive();\n\n this.isReclaiming = false;\n this.emit('joining', false);\n this._retries = 0;\n resolve(json);\n }).catch(error => {\n this.isReclaiming = false;\n this.emit('joining', false);\n reject({\n type: 'error',\n id: 11,\n message: 'reconnection error',\n data: error\n });\n });\n }; // this is called before 'close' event callback so it doesn't break reconnect loop\n\n\n this.ws.onerror = e => {\n this._abortController.signal.removeEventListener('abort', abortReconnect);\n\n this.isReclaiming = false;\n this.emit('joining', false);\n reject({\n type: 'warning',\n id: 12,\n message: 'ws reconnection error',\n data: e\n });\n };\n\n this._abortController.signal.addEventListener('abort', abortReconnect);\n });\n }\n\n connect(roomId, pin, server, iceServers, token, display, userId) {\n let webrtcVersion = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 0;\n let initialBitrate = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : 0;\n let recordingFilename = arguments.length > 9 ? arguments[9] : undefined;\n\n if (this.isConnecting) {\n return Promise.reject({\n type: 'warning',\n id: 16,\n message: 'connection already in progress'\n });\n }\n\n if (this.ws) {\n this._wipeListeners();\n }\n\n this._stopKeepAlive();\n\n this._abortController = new AbortController();\n this.sessionId = null;\n this.server = server;\n this.iceServers = iceServers;\n this.token = token;\n this.roomId = roomId;\n this.pin = pin;\n this.display = display;\n this.userId = userId;\n this.webrtcVersion = webrtcVersion;\n this.initialBitrate = initialBitrate;\n this.recordingFilename = recordingFilename;\n this.isConnecting = true;\n this.emit('joining', true);\n return new Promise((resolve, reject) => {\n this.ws = new WebSocket(this.server, 'janus-protocol');\n this.__connectionClosedBoundFn = this._connectionClosed.bind(this);\n this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);\n\n let abortConnect = () => {\n this._abortController.signal.removeEventListener('abort', abortConnect);\n\n this.ws.removeEventListener('close', this.__connectionClosedBoundFn);\n this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);\n this.ws.onopen = null;\n this.ws.onerror = null;\n this.isConnecting = false;\n this.emit('joining', false);\n reject({\n type: 'warning',\n id: 17,\n message: 'Connection cancelled'\n });\n };\n\n this.ws.addEventListener('close', this.__connectionClosedBoundFn);\n this.ws.addEventListener('message', this.__handleWsEventsBoundFn);\n\n this.ws.onopen = () => {\n this._abortController.signal.removeEventListener('abort', abortConnect);\n\n this._retries = 0;\n\n this._send({\n \"janus\": \"create\"\n }).then(json => {\n this.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n this._startKeepAlive();\n\n return 1;\n }).then(() => this._createParticipant(userId)).then(handle => {\n this.handleId = handle.handleId;\n return 1;\n }).then(() => this._joinRoom(roomId, pin, userId, display)).then(() => {\n this.isConnecting = false;\n this.emit('joining', false);\n resolve(this);\n }).catch(error => {\n this.isConnecting = false;\n this.emit('joining', false);\n reject({\n type: (error === null || error === void 0 ? void 0 : error.type) === 'warning' ? 'warning' : 'error',\n id: 13,\n message: 'connection error',\n data: error\n });\n });\n };\n\n this.ws.onerror = e => {\n this._abortController.signal.removeEventListener('abort', abortConnect);\n\n this.isConnecting = false;\n this.emit('joining', false);\n reject({\n type: 'error',\n id: 14,\n message: 'ws connection error',\n data: e\n });\n };\n\n this._abortController.signal.addEventListener('abort', abortConnect);\n });\n }\n\n disconnect() {\n var _this$_abortControlle, _this$_abortControlle2;\n\n if (this.isDisconnecting) {\n return Promise.resolve();\n }\n\n (_this$_abortControlle = this._abortController) === null || _this$_abortControlle === void 0 ? void 0 : (_this$_abortControlle2 = _this$_abortControlle.abort) === null || _this$_abortControlle2 === void 0 ? void 0 : _this$_abortControlle2.call(_this$_abortControlle);\n\n this._stopKeepAlive();\n\n let isConnected = this.isConnected;\n this.isDisconnecting = true;\n return Promise.all(this._participants.map(p => this._removeParticipant(p.handleId))).finally(() => {\n this._wipeListeners();\n\n if (this.ws && this.ws.readyState === 1) {\n this._send({\n \"janus\": \"destroy\"\n }, true);\n\n this.ws.close();\n }\n\n this.sessionId = null;\n this.isPublished = false;\n this.isConnected = false;\n this.isDisconnecting = false;\n this.emit('publishing', false);\n this.emit('published', {\n status: false,\n hasStream: false\n });\n this.emit('joining', false);\n this.emit('joined', false);\n this.emit('disconnect', isConnected);\n return Promise.resolve('Disconnected');\n });\n }\n\n startStream(streamId, server, iceServers, token, userId) {\n if (this.isConnecting) {\n return Promise.reject({\n type: 'warning',\n id: 16,\n message: 'connection error',\n data: 'Connection is in progress'\n });\n }\n\n if (this.ws) {\n this._wipeListeners();\n }\n\n this._stopKeepAlive();\n\n this._abortController = new AbortController();\n this.server = server;\n this.iceServers = iceServers;\n this.token = token;\n this.streamId = streamId;\n this.userId = userId;\n this.sessionId = null;\n this.isConnecting = true;\n this.emit('streamStarting', true);\n return new Promise((resolve, reject) => {\n this.ws = new WebSocket(this.server, 'janus-protocol');\n this.__connectionClosedBoundFn = this._connectionClosed.bind(this);\n this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);\n\n let abortConnect = () => {\n this._abortController.signal.removeEventListener('abort', abortConnect);\n\n this.ws.removeEventListener('close', this.__connectionClosedBoundFn);\n this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);\n this.ws.onopen = null;\n this.ws.onerror = null;\n this.isConnecting = false;\n this.emit('streamStarting', false);\n reject({\n type: 'warning',\n id: 17,\n message: 'Connection cancelled'\n });\n };\n\n this.ws.addEventListener('close', this.__connectionClosedBoundFn);\n this.ws.addEventListener('message', this.__handleWsEventsBoundFn);\n\n this.ws.onopen = () => {\n this._abortController.signal.removeEventListener('abort', abortConnect);\n\n this._retries = 0;\n\n this._send({\n \"janus\": \"create\"\n }).then(json => {\n this.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n this._startKeepAlive();\n\n return 1;\n }).then(() => this._createParticipant(userId)).then(handle => {\n this.handleId = handle.handleId;\n return 1;\n }).then(() => this._watchStream(streamId)).then(() => {\n this.isConnecting = false;\n this.emit('streamStarting', false);\n resolve(this);\n }).catch(error => {\n this.isConnecting = false;\n this.emit('streamStarting', false);\n reject({\n type: 'error',\n id: 13,\n message: 'connection error',\n data: error\n });\n });\n };\n\n this.ws.onerror = e => {\n this._abortController.signal.removeEventListener('abort', abortConnect);\n\n this.isConnecting = false;\n this.emit('streamStarting', false);\n reject({\n type: 'error',\n id: 14,\n message: 'ws connection error',\n data: e\n });\n };\n\n this._abortController.signal.addEventListener('abort', abortConnect);\n });\n }\n\n stopStream() {\n var _this$_abortControlle3, _this$_abortControlle4;\n\n if (this.isDisconnecting) {\n return Promise.resolve();\n }\n\n (_this$_abortControlle3 = this._abortController) === null || _this$_abortControlle3 === void 0 ? void 0 : (_this$_abortControlle4 = _this$_abortControlle3.abort) === null || _this$_abortControlle4 === void 0 ? void 0 : _this$_abortControlle4.call(_this$_abortControlle3);\n\n this._stopKeepAlive();\n\n let isStreaming = this.isStreaming;\n this.isDisconnecting = true;\n return this.sendMessage(this.handleId, {\n body: {\n \"request\": \"stop\"\n }\n }, false, true).then(() => this._removeParticipant(this.handleId)).finally(() => {\n this._wipeListeners();\n\n this._send({\n \"janus\": \"destroy\"\n }, true);\n\n if (this.ws && this.ws.readyState === 1) {\n this.ws.close();\n }\n\n this.sessionId = null;\n this.isDisconnecting = false;\n this.isStreaming = false;\n this.emit('streamStarting', false);\n this.emit('streaming', false);\n this.emit('disconnect', isStreaming);\n return Promise.resolve('Disconnected');\n });\n }\n\n destroy() {\n if (this.sessiontype === 'reactooroom') {\n return this.disconnect().then(() => {\n this.clear();\n return true;\n });\n } else if (this.sessiontype === 'streaming') {\n return this.stopStream().then(() => {\n this.clear();\n return true;\n });\n }\n }\n\n _enableDebug() {\n this._log = console.log.bind(console);\n }\n\n _getHandle(handleId) {\n let rfid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n return this._participants.find(p => p.handleId === handleId || rfid && p.rfid === rfid);\n }\n\n _getStats() {\n let type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n return Promise.all(this._participants.map(participant => {\n let mediaTrack = null;\n\n if (type === 'video') {\n mediaTrack = participant.webrtcStuff && participant.webrtcStuff.stream && participant.webrtcStuff.stream.getVideoTracks().length && participant.webrtcStuff.stream.getVideoTracks()[0];\n } else if (type === 'audio') {\n mediaTrack = participant.webrtcStuff && participant.webrtcStuff.stream && participant.webrtcStuff.stream.getAudioTracks().length && participant.webrtcStuff.stream.getAudioTracks()[0];\n }\n\n return participant.webrtcStuff && participant.webrtcStuff.pc && participant.webrtcStuff.pc.getStats(mediaTrack).then(r => ({\n handle: participant,\n stats: r\n })).catch(e => Promise.resolve({\n handle: participant,\n stats: e\n }));\n }));\n }\n\n _sendTrickleCandidate(handleId, candidate) {\n return this._send({\n \"janus\": \"trickle\",\n \"candidate\": candidate,\n \"handle_id\": handleId\n });\n }\n\n _webrtc(handleId) {\n let enableOntrack = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n this.emit('error', {\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'create rtc connection']\n });\n }\n\n let config = handle.webrtcStuff;\n\n if (!config.pc) {\n let pc_config = {\n \"iceServers\": this.iceServers,\n \"iceTransportPolicy\": 'all',\n \"bundlePolicy\": undefined\n };\n pc_config[\"sdpSemantics\"] = this.isUnifiedPlan ? \"unified-plan\" : \"plan-b\";\n let pc_constraints = {\n \"optional\": [{\n \"DtlsSrtpKeyAgreement\": true\n }]\n };\n\n if (this._ipv6Support === true) {\n pc_constraints.optional.push({\n \"googIPv6\": true\n });\n }\n\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === \"edge\") {\n // This is Edge, enable BUNDLE explicitly\n pc_config.bundlePolicy = \"max-bundle\";\n }\n\n this._log('new RTCPeerConnection', pc_config, pc_constraints);\n\n config.pc = new RTCPeerConnection(pc_config, pc_constraints);\n\n config.pc.onconnectionstatechange = () => {\n if (config.pc.connectionState === 'failed') {\n this._iceRestart(handleId);\n }\n\n this.emit('connectionState', [handleId, handleId === this.handleId, config.pc.connectionState]);\n\n if (handleId !== this.handleId && config.pc.connectionState === 'connected') {\n var _decodeJanusDisplay9, _decodeJanusDisplay10;\n\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: (_decodeJanusDisplay9 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay9 === void 0 ? void 0 : _decodeJanusDisplay9.userId,\n role: (_decodeJanusDisplay10 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay10 === void 0 ? void 0 : _decodeJanusDisplay10.role,\n stream: config.stream,\n track: null,\n optional: true,\n constructId: this.constructId,\n metaData: this.options.metaData,\n adding: false,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n }\n };\n\n config.pc.oniceconnectionstatechange = () => {\n if (config.pc.iceConnectionState === 'failed') {\n this._iceRestart(handleId);\n }\n\n this.emit('iceState', [handleId, handleId === this.handleId, config.pc.iceConnectionState]);\n\n if (handleId !== this.handleId && (config.pc.iceConnectionState === 'completed' || config.pc.iceConnectionState === 'connected')) {\n var _decodeJanusDisplay11, _decodeJanusDisplay12;\n\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: (_decodeJanusDisplay11 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay11 === void 0 ? void 0 : _decodeJanusDisplay11.userId,\n role: (_decodeJanusDisplay12 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay12 === void 0 ? void 0 : _decodeJanusDisplay12.role,\n stream: config.stream,\n track: null,\n optional: true,\n constructId: this.constructId,\n metaData: this.options.metaData,\n adding: false,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n }\n };\n\n config.pc.onicecandidate = event => {\n if (event.candidate == null || webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'edge' && event.candidate.candidate.indexOf('endOfCandidates') > 0) {\n config.iceDone = true;\n\n this._sendTrickleCandidate(handleId, {\n \"completed\": true\n }).catch(e => {\n this.emit('error', e);\n });\n } else {\n // JSON.stringify doesn't work on some WebRTC objects anymore\n // See https://code.google.com/p/chromium/issues/detail?id=467366\n var candidate = {\n \"candidate\": event.candidate.candidate,\n \"sdpMid\": event.candidate.sdpMid,\n \"sdpMLineIndex\": event.candidate.sdpMLineIndex\n };\n\n this._sendTrickleCandidate(handleId, candidate).catch(e => {\n this.emit('error', e);\n });\n }\n };\n\n if (enableOntrack) {\n config.pc.ontrack = event => {\n if (!event.streams) return; //config.stream = event.streams[0];\n\n if (!config.stream) {\n config.stream = new MediaStream();\n }\n\n if (event.track) {\n var _decodeJanusDisplay13, _decodeJanusDisplay14;\n\n let mid = event.transceiver ? event.transceiver.mid : event.track.id;\n config.stream.addTrack(event.track);\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n mid,\n id: handle.handleId,\n userId: (_decodeJanusDisplay13 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay13 === void 0 ? void 0 : _decodeJanusDisplay13.userId,\n role: (_decodeJanusDisplay14 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay14 === void 0 ? void 0 : _decodeJanusDisplay14.role,\n stream: config.stream,\n track: event.track,\n constructId: this.constructId,\n metaData: this.options.metaData,\n adding: true,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n if (event.track.onended) return;\n\n event.track.onended = ev => {\n let mid = ev.target.id;\n\n if (this.isUnifiedPlan) {\n let transceiver = config.pc.getTransceivers().find(t => t.receiver.track === ev.target);\n mid = transceiver.mid;\n }\n\n if (config.stream) {\n var _decodeJanusDisplay15, _decodeJanusDisplay16;\n\n config.stream && config.stream.removeTrack(ev.target);\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n mid,\n userId: (_decodeJanusDisplay15 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay15 === void 0 ? void 0 : _decodeJanusDisplay15.userId,\n role: (_decodeJanusDisplay16 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay16 === void 0 ? void 0 : _decodeJanusDisplay16.role,\n stream: config.stream,\n track: ev.target,\n constructId: this.constructId,\n metaData: this.options.metaData,\n adding: false,\n removing: true,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n }\n };\n\n event.track.onmute = ev => {\n var _decodeJanusDisplay17, _decodeJanusDisplay18;\n\n this._log('remoteTrackMuted', 'onmute');\n\n let mid = ev.target.id;\n\n if (this.isUnifiedPlan) {\n let transceiver = config.pc.getTransceivers().find(t => t.receiver.track === ev.target);\n mid = transceiver.mid;\n }\n\n this.emit('remoteTrackMuted', {\n id: handle.handleId,\n mid,\n userId: (_decodeJanusDisplay17 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay17 === void 0 ? void 0 : _decodeJanusDisplay17.userId,\n role: (_decodeJanusDisplay18 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay18 === void 0 ? void 0 : _decodeJanusDisplay18.role,\n stream: config.stream,\n kind: ev.target.kind,\n track: ev.target,\n muted: true\n });\n };\n\n event.track.onunmute = ev => {\n var _decodeJanusDisplay19, _decodeJanusDisplay20;\n\n this._log('remoteTrackMuted', 'onunmute');\n\n let mid = ev.target.id;\n\n if (this.isUnifiedPlan) {\n let transceiver = config.pc.getTransceivers().find(t => t.receiver.track === ev.target);\n mid = transceiver.mid;\n }\n\n this.emit('remoteTrackMuted', {\n id: handle.handleId,\n mid,\n userId: (_decodeJanusDisplay19 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay19 === void 0 ? void 0 : _decodeJanusDisplay19.userId,\n role: (_decodeJanusDisplay20 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay20 === void 0 ? void 0 : _decodeJanusDisplay20.role,\n stream: config.stream,\n kind: ev.target.kind,\n track: ev.target,\n muted: false\n });\n };\n }\n };\n }\n }\n\n if (!config.dataChannel || !config.dataChannelOpen) {\n config.dataChannel = {};\n\n var onDataChannelMessage = event => {\n this._handleDataEvents(handleId, 'message', event.data);\n };\n\n var onDataChannelStateChange = event => {\n let label = event.target.label;\n let protocol = event.target.protocol;\n let state = config.dataChannel[label] ? config.dataChannel[label].readyState : \"null\";\n\n this._handleDataEvents(handleId, 'state', {\n state,\n label\n });\n }; //TODO: check this\n\n\n var onDataChannelError = error => {\n var _error$channel;\n\n this._handleDataEvents(handleId, 'error', {\n label: error === null || error === void 0 ? void 0 : (_error$channel = error.channel) === null || _error$channel === void 0 ? void 0 : _error$channel.label,\n error\n });\n };\n\n const createDataChannel = (label, protocol, incoming) => {\n let options = {\n ordered: true\n };\n\n if (!incoming) {\n if (protocol) {\n options = { ...options,\n protocol\n };\n }\n\n config.dataChannel[label] = config.pc.createDataChannel(label, options);\n } else {\n config.dataChannel[label] = incoming;\n }\n\n config.dataChannel[label].onmessage = onDataChannelMessage;\n config.dataChannel[label].onopen = onDataChannelStateChange;\n config.dataChannel[label].onclose = onDataChannelStateChange;\n config.dataChannel[label].onerror = onDataChannelError;\n };\n\n createDataChannel(this.defaultDataChannelLabel, null, null);\n\n config.pc.ondatachannel = function (event) {\n createDataChannel(event.channel.label, event.channel.protocol, event.channel);\n };\n }\n }\n\n _webrtcPeer(handleId, jsep) {\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'rtc peer']\n });\n }\n\n var config = handle.webrtcStuff;\n\n if (jsep !== undefined && jsep !== null) {\n if (config.pc === null) {\n this._log(\"No PeerConnection: if this is an answer, use createAnswer and not _webrtcPeer\");\n\n return Promise.resolve(null);\n }\n\n return config.pc.setRemoteDescription(jsep).then(() => {\n config.remoteSdp = jsep.sdp; // Any trickle candidate we cached?\n\n if (config.candidates && config.candidates.length > 0) {\n for (var i = 0; i < config.candidates.length; i++) {\n var candidate = config.candidates[i];\n\n if (!candidate || candidate.completed === true) {\n config.pc.addIceCandidate(null);\n } else {\n config.pc.addIceCandidate(candidate);\n }\n }\n\n config.candidates = [];\n } // Done\n\n\n return true;\n });\n } else {\n return Promise.reject({\n type: 'warning',\n id: 22,\n message: 'rtc peer',\n data: [handleId, 'invalid jsep']\n });\n }\n }\n\n _iceRestart(handleId) {\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n return;\n }\n\n var config = handle.webrtcStuff; // Already restarting;\n\n if (config.isIceRestarting) {\n return;\n }\n\n if (this.handleId === handleId) {\n this._log('Performing local ICE restart');\n\n config.isIceRestarting = true;\n let hasAudio = !!(config.stream && config.stream.getAudioTracks().length > 0);\n let hasVideo = !!(config.stream && config.stream.getVideoTracks().length > 0);\n\n this._createAO('offer', handleId, true, [hasAudio, false, hasVideo, false]).then(jsep => {\n if (!jsep) {\n return null;\n }\n\n return this.sendMessage(handleId, {\n body: {\n \"request\": \"configure\",\n \"audio\": hasAudio,\n \"video\": hasVideo,\n \"data\": true,\n ...(this.recordingFilename ? {\n filename: this.recordingFilename\n } : {})\n },\n jsep\n });\n }).then(r => {\n config.isIceRestarting = false;\n\n this._log('ICE restart success');\n }).catch(e => {\n config.isIceRestarting = false;\n this.emit('warning', {\n type: 'error',\n id: 28,\n message: 'iceRestart failed',\n data: e\n });\n });\n } else {\n this._log('Performing remote ICE restart', handleId);\n\n config.isIceRestarting = true;\n return this.sendMessage(handleId, {\n body: {\n \"request\": \"configure\",\n \"restart\": true\n }\n }).then(() => {\n config.isIceRestarting = false;\n }).catch(() => {\n config.isIceRestarting = false;\n });\n }\n }\n\n _createAO() {\n let type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'offer';\n let handleId = arguments.length > 1 ? arguments[1] : undefined;\n let iceRestart = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n let [audioSend, audioRecv, videoSend, videoRecv] = arguments.length > 3 ? arguments[3] : undefined;\n\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'createAO', type]\n });\n }\n\n let methodName = null;\n\n if (type === 'offer') {\n methodName = 'createOffer';\n } else {\n methodName = 'createAnswer';\n }\n\n var config = handle.webrtcStuff; // https://code.google.com/p/webrtc/issues/detail?id=3508\n\n var mediaConstraints = {};\n\n if (this.isUnifiedPlan) {\n var audioTransceiver = null,\n videoTransceiver = null;\n var transceivers = config.pc.getTransceivers();\n\n if (transceivers && transceivers.length > 0) {\n for (var i in transceivers) {\n var t = transceivers[i];\n\n if (t.sender && t.sender.track && t.sender.track.kind === \"audio\" && t.stopped === false || t.receiver && t.receiver.track && t.receiver.track.kind === \"audio\" && t.stopped === false) {\n if (!audioTransceiver) audioTransceiver = t;\n continue;\n }\n\n if (t.sender && t.sender.track && t.sender.track.kind === \"video\" && t.stopped === false || t.receiver && t.receiver.track && t.receiver.track.kind === \"video\" && t.stopped === false) {\n if (!videoTransceiver) videoTransceiver = t;\n continue;\n }\n }\n } // Handle audio (and related changes, if any)\n\n\n if (!audioSend && !audioRecv) {\n // Audio disabled: have we removed it?\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"inactive\");\n } else {\n audioTransceiver.direction = \"inactive\";\n }\n }\n } else {\n // Take care of audio m-line\n if (audioSend && audioRecv) {\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"sendrecv\");\n } else {\n audioTransceiver.direction = \"sendrecv\";\n }\n }\n } else if (audioSend && !audioRecv) {\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"sendonly\");\n } else {\n audioTransceiver.direction = \"sendonly\";\n }\n }\n } else if (!audioSend && audioRecv) {\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"recvonly\");\n } else {\n audioTransceiver.direction = \"recvonly\";\n }\n } else {\n // In theory, this is the only case where we might not have a transceiver yet\n audioTransceiver = config.pc.addTransceiver(\"audio\", {\n direction: \"recvonly\"\n });\n }\n }\n } // Handle video (and related changes, if any)\n\n\n if (!videoSend && !videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"inactive\");\n } else {\n videoTransceiver.direction = \"inactive\";\n }\n }\n } else {\n // Take care of video m-line\n if (videoSend && videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"sendrecv\");\n } else {\n videoTransceiver.direction = \"sendrecv\";\n }\n }\n } else if (videoSend && !videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"sendonly\");\n } else {\n videoTransceiver.direction = \"sendonly\";\n }\n }\n } else if (!videoSend && videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"recvonly\");\n } else {\n videoTransceiver.direction = \"recvonly\";\n }\n } else {\n // In theory, this is the only case where we might not have a transceiver yet\n videoTransceiver = config.pc.addTransceiver(\"video\", {\n direction: \"recvonly\"\n });\n }\n }\n }\n } else {\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === \"firefox\" || webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === \"edge\") {\n mediaConstraints = {\n offerToReceiveAudio: audioRecv,\n offerToReceiveVideo: videoRecv\n };\n } else {\n mediaConstraints = {\n mandatory: {\n OfferToReceiveAudio: audioRecv,\n OfferToReceiveVideo: videoRecv\n }\n };\n }\n }\n\n if (iceRestart) {\n mediaConstraints[\"iceRestart\"] = true;\n }\n\n return config.pc[methodName](mediaConstraints).then(function (response) {\n config.mySdp = response.sdp;\n\n let _p = config.pc.setLocalDescription(response).catch(e => {\n return Promise.reject({\n type: 'warning',\n id: 24,\n message: 'setLocalDescription',\n data: [handleId, e]\n });\n });\n\n config.mediaConstraints = mediaConstraints;\n\n if (!config.iceDone && !config.trickle) {\n // Don't do anything until we have all candidates\n return Promise.resolve(null);\n } // JSON.stringify doesn't work on some WebRTC objects anymore\n // See https://code.google.com/p/chromium/issues/detail?id=467366\n\n\n var jsep = {\n \"type\": response.type,\n \"sdp\": response.sdp\n };\n return _p.then(() => jsep);\n }, e => {\n return Promise.reject({\n type: 'warning',\n id: 25,\n message: methodName,\n data: [handleId, e]\n });\n });\n }\n\n _publishRemote(handleId, jsep) {\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'publish remote participant']\n });\n }\n\n this._webrtc(handleId, true);\n\n let config = handle.webrtcStuff;\n\n if (jsep) {\n return config.pc.setRemoteDescription(jsep).then(() => {\n config.remoteSdp = jsep.sdp; // Any trickle candidate we cached?\n\n if (config.candidates && config.candidates.length > 0) {\n for (var i = 0; i < config.candidates.length; i++) {\n var candidate = config.candidates[i];\n\n if (!candidate || candidate.completed === true) {\n // end-of-candidates\n config.pc.addIceCandidate(null);\n } else {\n // New candidate\n config.pc.addIceCandidate(candidate);\n }\n }\n\n config.candidates = [];\n } // Create the answer now\n\n\n return this._createAO('answer', handleId, false, [false, true, false, true]).then(_jsep => {\n if (!_jsep) {\n this.emit('error', {\n type: 'warning',\n id: 19,\n message: 'publish remote participant',\n data: [handleId, 'no jsep']\n });\n return Promise.resolve();\n }\n\n return this.sendMessage(handleId, {\n \"body\": {\n \"request\": \"start\",\n ...(this.roomId && {\n \"room\": this.roomId\n }),\n ...(this.pin && {\n pin: this.pin\n })\n },\n \"jsep\": _jsep\n });\n });\n }, e => Promise.reject({\n type: 'warning',\n id: 23,\n message: 'setRemoteDescription',\n data: [handleId, e]\n }));\n } else {\n return Promise.resolve();\n }\n } //Public methods\n\n\n publishLocal(stream) {\n let {\n keepAudio = false,\n keepVideo = false\n } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n if (this.isDisconnecting || !this.isConnected) {\n return Promise.reject({\n type: 'warning',\n id: 18,\n message: 'Either not connected or disconnecting'\n });\n }\n\n this.emit('publishing', true);\n\n let handle = this._getHandle(this.handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'error',\n id: 21,\n message: 'no local id, connect before publishing',\n data: null\n });\n }\n\n this._webrtc(this.handleId);\n\n let config = handle.webrtcStuff;\n\n if (stream) {\n if (!config.stream) {\n config.stream = stream;\n stream.getTracks().forEach(function (track) {\n config.pc.addTrack(track, stream);\n });\n } else {\n /* UPDATE Audio */\n let replaceAudio = stream.getAudioTracks().length;\n\n if (replaceAudio || !keepAudio) {\n //this will stop existing tracks\n let oldAudioStream = config.stream.getAudioTracks()[0];\n\n if (oldAudioStream) {\n config.stream.removeTrack(oldAudioStream);\n\n try {\n oldAudioStream.stop();\n } catch (e) {\n this._log(e);\n }\n }\n }\n\n if (config.pc.getSenders() && config.pc.getSenders().length) {\n if (replaceAudio && this.isUnifiedPlan) {//using replace\n } else {\n for (let index in config.pc.getSenders()) {\n let s = config.pc.getSenders()[index];\n\n if (s && s.track && s.track.kind === \"audio\") {\n config.pc.removeTrack(s);\n }\n }\n }\n }\n\n if (replaceAudio) {\n config.stream.addTrack(stream.getAudioTracks()[0]);\n var audioTransceiver = null;\n\n if (this.isUnifiedPlan) {\n let transceivers = config.pc.getTransceivers();\n\n if (transceivers && transceivers.length > 0) {\n for (let i in transceivers) {\n let t = transceivers[i];\n\n if (t.sender && t.sender.track && t.sender.track.kind === \"audio\" && t.stopped === false || t.receiver && t.receiver.track && t.receiver.track.kind === \"audio\" && t.stopped === false) {\n audioTransceiver = t;\n break;\n }\n }\n }\n }\n\n if (audioTransceiver && audioTransceiver.sender) {\n audioTransceiver.sender.replaceTrack(stream.getAudioTracks()[0]);\n } else {\n config.pc.addTrack(stream.getAudioTracks()[0], stream);\n }\n }\n /* UPDATE Video */\n\n\n let replaceVideo = stream.getVideoTracks().length;\n\n if (replaceVideo || !keepVideo) {\n let oldVideoStream = config.stream.getVideoTracks()[0];\n\n if (oldVideoStream) {\n config.stream.removeTrack(oldVideoStream);\n\n try {\n oldVideoStream.stop();\n } catch (e) {\n this._log(e);\n }\n }\n }\n\n if (config.pc.getSenders() && config.pc.getSenders().length) {\n if (replaceVideo && this.isUnifiedPlan) {//using replace\n } else {\n for (let index in config.pc.getSenders()) {\n let s = config.pc.getSenders()[index];\n\n if (s && s.track && s.track.kind === \"video\") {\n config.pc.removeTrack(s);\n }\n }\n }\n }\n\n if (replaceVideo) {\n config.stream.addTrack(stream.getVideoTracks()[0]);\n var videoTransceiver = null;\n\n if (this.isUnifiedPlan) {\n let transceivers = config.pc.getTransceivers();\n\n if (transceivers && transceivers.length > 0) {\n for (let i in transceivers) {\n let t = transceivers[i];\n\n if (t.sender && t.sender.track && t.sender.track.kind === \"video\" && t.stopped === false || t.receiver && t.receiver.track && t.receiver.track.kind === \"video\" && t.stopped === false) {\n videoTransceiver = t;\n break;\n }\n }\n }\n }\n\n if (videoTransceiver && videoTransceiver.sender) {\n //TODO: check if t.stopped === false still gets us videoTransceiver\n videoTransceiver.sender.replaceTrack(stream.getVideoTracks()[0]);\n } else {\n config.pc.addTrack(stream.getVideoTracks()[0], stream);\n }\n }\n }\n }\n\n let hasAudio = !!(stream && stream.getAudioTracks().length > 0);\n let hasVideo = !!(stream && stream.getVideoTracks().length > 0);\n let isAudioMuted = !stream || stream.getAudioTracks().length === 0 || !stream.getAudioTracks()[0].enabled;\n let isVideoMuted = !stream || stream.getVideoTracks().length === 0 || !stream.getVideoTracks()[0].enabled;\n this.isAudioEnabed = hasAudio;\n this.isVideoEnabled = hasVideo;\n this.isAudioMuted = isAudioMuted;\n this.isVideoMuted = isVideoMuted;\n return this._createAO('offer', this.handleId, false, [hasAudio, false, hasVideo, false]).then(jsep => {\n if (!jsep) {\n return null;\n } //HOTFIX: Temporary fix for Safari 13\n\n\n if (jsep.sdp && jsep.sdp.indexOf(\"\\r\\na=ice-ufrag\") === -1) {\n jsep.sdp = jsep.sdp.replace(\"\\na=ice-ufrag\", \"\\r\\na=ice-ufrag\");\n }\n\n return this.sendMessage(this.handleId, {\n body: {\n \"request\": \"configure\",\n \"audio\": hasAudio,\n \"video\": hasVideo,\n \"data\": true,\n ...(this.recordingFilename ? {\n filename: this.recordingFilename\n } : {})\n },\n jsep\n });\n }).then(r => {\n if (this._isDataChannelOpen) {\n return Promise.resolve(r);\n } else {\n return new Promise((resolve, reject) => {\n let dataChannelTimeoutId = null;\n\n let _resolve = val => {\n if (val) {\n clearTimeout(dataChannelTimeoutId);\n\n this._abortController.signal.removeEventListener('abort', _rejectAbort);\n\n this.off('dataChannel', _resolve, this);\n resolve(this);\n }\n };\n\n let _rejectTimeout = () => {\n this.off('dataChannel', _resolve, this);\n\n this._abortController.signal.removeEventListener('abort', _rejectAbort);\n\n reject({\n type: 'error',\n id: 27,\n message: 'Data channel did not open',\n data: null\n });\n };\n\n let _rejectAbort = () => {\n this._abortController.signal.removeEventListener('abort', _rejectAbort);\n\n clearTimeout(dataChannelTimeoutId);\n this.off('dataChannel', _resolve, this);\n reject({\n type: 'warning',\n id: 17,\n message: 'Connection cancelled'\n });\n };\n\n dataChannelTimeoutId = setTimeout(_rejectTimeout, 5000);\n\n this._abortController.signal.addEventListener('abort', _rejectAbort);\n\n this.on('dataChannel', _resolve, this);\n });\n }\n }).then(r => {\n this.isPublished = true;\n\n if (config.stream) {\n let tracks = config.stream.getTracks();\n tracks.forEach(track => {\n // used as a flag to not emit tracks that been already emitted\n if (!track.onended) {\n var _decodeJanusDisplay21, _decodeJanusDisplay22;\n\n this.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: (_decodeJanusDisplay21 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay21 === void 0 ? void 0 : _decodeJanusDisplay21.userId,\n role: (_decodeJanusDisplay22 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay22 === void 0 ? void 0 : _decodeJanusDisplay22.role,\n track,\n stream: config.stream,\n adding: true,\n constructId: this.constructId,\n metaData: this.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n\n track.onended = ev => {\n var _decodeJanusDisplay23, _decodeJanusDisplay24;\n\n this.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: (_decodeJanusDisplay23 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay23 === void 0 ? void 0 : _decodeJanusDisplay23.userId,\n role: (_decodeJanusDisplay24 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay24 === void 0 ? void 0 : _decodeJanusDisplay24.role,\n track: ev.target,\n stream: config.stream,\n adding: false,\n removing: true,\n constructId: this.constructId,\n metaData: this.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n };\n }\n });\n } else {\n var _decodeJanusDisplay25, _decodeJanusDisplay26;\n\n this.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: (_decodeJanusDisplay25 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay25 === void 0 ? void 0 : _decodeJanusDisplay25.userId,\n role: (_decodeJanusDisplay26 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay26 === void 0 ? void 0 : _decodeJanusDisplay26.role,\n stream: null,\n adding: false,\n constructId: this.constructId,\n metaData: this.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n }\n\n this.emit('published', {\n status: true,\n hasStream: !!config.stream\n });\n this.emit('publishing', false);\n this.emit('localHasVideo', hasVideo);\n this.emit('localHasAudio', hasAudio);\n this.emit('localMuted', {\n type: 'video',\n value: isVideoMuted\n });\n this.emit('localMuted', {\n type: 'audio',\n value: isAudioMuted\n });\n return r;\n }).catch(e => {\n this.emit('publishing', false);\n return Promise.reject(e);\n });\n }\n\n unpublishLocal() {\n let dontWait = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n return this.isPublished ? this.sendMessage(this.handleId, {\n body: {\n \"request\": \"unpublish\"\n }\n }, dontWait).finally(r => {\n this.isPublished = false;\n this.emit('published', {\n status: false,\n hasStream: false\n });\n return r;\n }) : Promise.resolve();\n }\n\n toggleAudio() {\n let value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let mid = arguments.length > 1 ? arguments[1] : undefined;\n\n let handle = this._getHandle(this.handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'error',\n id: 21,\n message: 'no local id, connect first',\n data: null\n });\n }\n\n let config = handle.webrtcStuff;\n\n if (this.isUnifiedPlan) {\n let transceiver = config.pc.getTransceivers().find(t => t.sender && t.sender.track && t.receiver.track.kind === \"audio\" && t.stopped === false && (mid ? t.mid === mid : true));\n\n if (transceiver) {\n transceiver.sender.track.enabled = value !== null ? !!value : !transceiver.sender.track.enabled;\n }\n\n this.isAudioMuted = !transceiver || !transceiver.sender.track.enabled;\n } else {\n if (config.stream && config.stream.getAudioTracks().length) {\n config.stream.getAudioTracks()[0].enabled = value !== null ? !!value : !config.stream.getAudioTracks()[0].enabled;\n }\n\n this.isAudioMuted = config.stream.getAudioTracks().length === 0 || !config.stream.getAudioTracks()[0].enabled;\n }\n\n this.emit('localMuted', {\n type: 'audio',\n value: this.isAudioMuted,\n mid\n });\n }\n\n toggleVideo() {\n let value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let mid = arguments.length > 1 ? arguments[1] : undefined;\n\n let handle = this._getHandle(this.handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'error',\n id: 21,\n message: 'no local id, connect first',\n data: null\n });\n }\n\n let config = handle.webrtcStuff;\n\n if (this.isUnifiedPlan) {\n let transceiver = config.pc.getTransceivers().find(t => t.sender && t.sender.track && t.receiver.track.kind === \"video\" && t.stopped === false && (mid ? t.mid === mid : true));\n\n if (transceiver) {\n transceiver.sender.track.enabled = value !== null ? !!value : !transceiver.sender.track.enabled;\n }\n\n this.isVideoMuted = !transceiver || !transceiver.sender.track.enabled;\n } else {\n if (config.stream && config.stream.getVideoTracks().length) {\n config.stream.getVideoTracks()[0].enabled = value !== null ? !!value : !config.stream.getVideoTracks()[0].enabled;\n }\n\n this.isVideoMuted = config.stream.getVideoTracks().length === 0 || !config.stream.getVideoTracks()[0].enabled;\n }\n\n this.emit('localMuted', {\n type: 'video',\n value: this.isVideoMuted,\n mid\n });\n }\n\n setRoomType() {\n let type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'watchparty';\n this._roomType = type;\n return this._roomType;\n }\n\n}\n\n_defineProperty(RoomSession, \"sessionTypes\", {\n 'reactooroom': 'janus.plugin.reactooroom',\n 'streaming': 'janus.plugin.streaming'\n});\n\n_defineProperty(RoomSession, \"subscriptionRules\", {\n participant: {\n \"watchparty\": ['participant', 'talkback'],\n \"commentary\": ['participant', 'talkback'],\n \"videowall\": ['host', 'talkback', 'observer', 'observerSolo1', 'observerSolo2', 'observerSolo3'],\n \"videowall-queue\": ['host', 'talkback', 'observer', 'observerSolo1', 'observerSolo2', 'observerSolo3'],\n \"videowall-queue-video\": ['host', 'talkback', 'observer', 'observerSolo1', 'observerSolo2', 'observerSolo3']\n },\n monitor: {\n \"watchparty\": ['participant'],\n \"commentary\": ['participant'],\n \"videowall\": ['host', 'participant'],\n \"videowall-queue\": ['host', 'participant'],\n \"videowall-queue-video\": ['host', 'participant']\n },\n talkback: {\n \"watchparty\": ['participant'],\n \"commentary\": ['participant'],\n \"videowall\": ['host', 'participant'],\n \"videowall-queue\": ['host', 'participant'],\n \"videowall-queue-video\": ['host', 'participant']\n },\n observer: {\n \"watchparty\": ['participant'],\n \"commentary\": ['participant'],\n \"videowall\": ['participant'],\n \"videowall-queue\": ['participant'],\n \"videowall-queue-video\": ['participant']\n },\n observerSolo1: {\n \"watchparty\": ['participant'],\n \"commentary\": ['participant'],\n \"videowall\": ['participant'],\n \"videowall-queue\": ['participant'],\n \"videowall-queue-video\": ['participant']\n },\n observerSolo2: {\n \"watchparty\": ['participant'],\n \"commentary\": ['participant'],\n \"videowall\": ['participant'],\n \"videowall-queue\": ['participant'],\n \"videowall-queue-video\": ['participant']\n },\n observerSolo3: {\n \"watchparty\": ['participant'],\n \"commentary\": ['participant'],\n \"videowall\": ['participant'],\n \"videowall-queue\": ['participant'],\n \"videowall-queue-video\": ['participant']\n },\n host: {\n \"watchparty\": [],\n \"commentary\": [],\n \"videowall\": [],\n \"videowall-queue\": [],\n \"videowall-queue-video\": []\n },\n companionTV: {},\n companionPhone: {}\n});\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Room);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-room.js?");
9430
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! webrtc-adapter */ \"./node_modules/webrtc-adapter/src/js/adapter_core.js\");\n/* harmony import */ var _wt_emitter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./wt-emitter */ \"./src/modules/wt-emitter.js\");\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./wt-utils */ \"./src/modules/wt-utils.js\");\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n// Watch together janus webrtc library\n\n\n\n\nclass Room {\n constructor(debug) {\n this.debug = debug;\n this.sessions = [];\n this.safariVp8 = false;\n this.browser = webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser;\n this.browserDetails = webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails;\n this.webrtcSupported = Room.isWebrtcSupported();\n this.safariVp8TestPromise = Room.testSafariVp8();\n this.safariVp8 = null;\n this.safariVp8TestPromise.then(safariVp8 => {\n this.safariVp8 = safariVp8;\n }); // Let's get it started\n\n this.whenInitialized = this.initialize();\n }\n\n initialize() {\n return this.safariVp8TestPromise.then(() => this);\n }\n\n createSession() {\n let constructId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'reactooroom';\n let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n return new RoomSession(constructId, type, {\n debug: this.debug,\n ...options\n });\n }\n\n static testSafariVp8() {\n return new Promise(resolve => {\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'safari' && webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.version >= 605) {\n if (RTCRtpSender && RTCRtpSender.getCapabilities && RTCRtpSender.getCapabilities(\"video\") && RTCRtpSender.getCapabilities(\"video\").codecs && RTCRtpSender.getCapabilities(\"video\").codecs.length) {\n var isVp8 = false;\n\n for (var i in RTCRtpSender.getCapabilities(\"video\").codecs) {\n var codec = RTCRtpSender.getCapabilities(\"video\").codecs[i];\n\n if (codec && codec.mimeType && codec.mimeType.toLowerCase() === \"video/vp8\") {\n isVp8 = true;\n break;\n }\n }\n\n resolve(isVp8);\n } else {\n // We do it in a very ugly way, as there's no alternative...\n // We create a PeerConnection to see if VP8 is in an offer\n var testpc = new RTCPeerConnection({}, {});\n testpc.createOffer({\n offerToReceiveVideo: true\n }).then(function (offer) {\n let result = offer.sdp.indexOf(\"VP8\") !== -1;\n testpc.close();\n testpc = null;\n resolve(result);\n });\n }\n } else resolve(false);\n });\n }\n\n static isWebrtcSupported() {\n return window.RTCPeerConnection !== undefined && window.RTCPeerConnection !== null && navigator.mediaDevices !== undefined && navigator.mediaDevices !== null && navigator.mediaDevices.getUserMedia !== undefined && navigator.mediaDevices.getUserMedia !== null;\n }\n\n}\n\nclass RoomSession {\n static noop() {}\n\n static randomString(len) {\n var charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n var randomString = '';\n\n for (var i = 0; i < len; i++) {\n var randomPoz = Math.floor(Math.random() * charSet.length);\n randomString += charSet.substring(randomPoz, randomPoz + 1);\n }\n\n return randomString;\n } //TODO: solve\n // #eventList = ['error', 'kicked', 'addLocalParticipant', ,'addRemoteInstructor','addRemoteParticipant','addRemoteTalkback', 'addRemoteObserver', 'removeRemoteInstructor', 'removeLocalParticipant', 'removeRemoteParticipant', 'removeRemoteTalkback', 'removeRemoteObserver', 'localMuted', 'localHasVideo', 'localHasAudio', 'data', 'iceState', 'connectionState', 'joined', 'joining', 'dataChannel', 'disconnect', 'observerIds', 'talkbackIds', 'instructorId', 'published', 'publishing', 'remoteTrackMuted', 'streamingStatus', 'streaming', 'streamStarting'];\n //\n\n\n constructor() {\n let constructId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'reactooroom';\n let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n Object.assign(this, Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])());\n this.defaultDataChannelLabel = 'JanusDataChannel';\n this.server = null;\n this.iceServers = null;\n this.token = null;\n this.roomId = null;\n this.streamId = null;\n this.pin = null;\n this.userId = null;\n this.sessiontype = type;\n this.initialBitrate = 0;\n this.recordingFilename = null;\n this.pluginName = RoomSession.sessionTypes[type];\n this.options = options;\n this.id = null;\n this.privateId = null;\n this.constructId = constructId || RoomSession.randomString(16);\n this.sessionId = null;\n this.handleId = null;\n this.ws = null;\n this.isRestarting = false;\n this.isConnecting = false;\n this.isDisconnecting = false;\n this.isConnected = false;\n this.isPublished = false;\n this.isReclaiming = false;\n this.isStreaming = false;\n this._ipv6Support = false;\n this._retries = 0;\n this._maxRetries = 3;\n this._keepAliveId = null;\n this._participants = [];\n this._roomType = 'watchparty';\n this._isDataChannelOpen = false;\n this._abortController = null;\n this.isAudioMuted = false;\n this.isVideoMuted = false;\n this.isVideoEnabled = false;\n this.isAudioEnabed = false;\n this.isUnifiedPlan = RoomSession.checkUnifiedPlan();\n this.subscriptionRules = { ...RoomSession.subscriptionRules,\n ...(this.options.subscriptionRules || {})\n };\n this._log = RoomSession.noop;\n\n if (this.options.debug) {\n this._enableDebug();\n }\n } // Check if this browser supports Unified Plan and transceivers\n // Based on https://codepen.io/anon/pen/ZqLwWV?editors=0010\n\n\n static checkUnifiedPlan() {\n let unifiedPlan = false;\n\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'firefox' && webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.version >= 59) {\n // Firefox definitely does, starting from version 59\n unifiedPlan = true;\n } else if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'chrome' && webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.version >= 72) {\n // Chrome does, but it's only usable from version 72 on\n unifiedPlan = true;\n } else if (!window.RTCRtpTransceiver || !('currentDirection' in RTCRtpTransceiver.prototype)) {\n // Safari supports addTransceiver() but not Unified Plan when\n // currentDirection is not defined (see codepen above).\n unifiedPlan = false;\n } else {\n // Check if addTransceiver() throws an exception\n const tempPc = new RTCPeerConnection();\n\n try {\n tempPc.addTransceiver('audio');\n unifiedPlan = true;\n } catch (e) {}\n\n tempPc.close();\n }\n\n return unifiedPlan;\n }\n\n _participantShouldSubscribe(userId) {\n const myUser = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(this.display);\n const remoteUser = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(userId);\n let localUserRole = (myUser === null || myUser === void 0 ? void 0 : myUser.role) || 'participant';\n let remoteUserRole = (remoteUser === null || remoteUser === void 0 ? void 0 : remoteUser.role) || 'participant';\n return this.subscriptionRules[localUserRole][this._roomType || 'watchparty'].indexOf(remoteUserRole) > -1;\n }\n\n _getAddParticipantEventName(handleId) {\n var _decodeJanusDisplay;\n\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n this.emit('error', {\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'getParticipantEventName']\n });\n }\n\n const participantRole = (_decodeJanusDisplay = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay === void 0 ? void 0 : _decodeJanusDisplay.role;\n\n switch (participantRole) {\n case 'participant':\n return 'addRemoteParticipant';\n\n case 'talkback':\n return 'addRemoteTalkback';\n\n case 'monitor':\n return 'addRemoteTalkback';\n\n case 'observer':\n case 'observerSolo1':\n case 'observerSolo2':\n case 'observerSolo3':\n return 'addRemoteObserver';\n\n case 'host':\n return 'addRemoteInstructor';\n\n case 'companionTV':\n return 'addRemoteCompanionTV';\n\n case 'companionPhone':\n return 'addRemoteCompanionPhone';\n\n default:\n return 'addRemoteParticipant';\n }\n }\n\n _getRemoveParticipantEventName(handleId) {\n var _decodeJanusDisplay2;\n\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n this.emit('error', {\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'getParticipantEventName']\n });\n }\n\n const participantRole = (_decodeJanusDisplay2 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay2 === void 0 ? void 0 : _decodeJanusDisplay2.role;\n\n switch (participantRole) {\n case 'participant':\n return 'removeRemoteParticipant';\n\n case 'talkback':\n return 'removeRemoteTalkback';\n\n case 'monitor':\n return 'removeRemoteTalkback';\n\n case 'observer':\n case 'observerSolo1':\n case 'observerSolo2':\n case 'observerSolo3':\n return 'removeRemoteObserver';\n\n case 'host':\n return 'removeRemoteInstructor';\n\n case 'companionTV':\n return 'removeRemoteCompanionTV';\n\n case 'companionPhone':\n return 'removeRemoteCompanionPhone';\n\n default:\n return 'removeRemoteParticipant';\n }\n }\n\n sendMessage(handleId) {\n let message = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n body: 'Example Body'\n };\n let dontWait = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n let dontResolveOnAck = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n return this._send({\n \"janus\": \"message\",\n \"handle_id\": handleId,\n ...message\n }, dontWait, dontResolveOnAck).then(json => {\n if (json && json[\"janus\"] === \"success\") {\n let plugindata = json[\"plugindata\"] || {};\n let data = plugindata[\"data\"];\n return Promise.resolve(data);\n }\n\n return Promise.resolve();\n }).catch(json => {\n if (json && json[\"error\"]) {\n return Promise.reject({\n type: 'warning',\n id: 1,\n message: 'sendMessage failed',\n data: json[\"error\"]\n });\n } else {\n return Promise.reject({\n type: 'warning',\n id: 1,\n message: 'sendMessage failed',\n data: json\n });\n }\n });\n }\n\n _send() {\n let request = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let ignoreResponse = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n let dontResolveOnAck = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n let transaction = RoomSession.randomString(12);\n let requestData = { ...request,\n transaction,\n token: this.token,\n ...(this.sessionId && {\n 'session_id': this.sessionId\n } || {})\n };\n\n this._log(requestData);\n\n return new Promise((resolve, reject) => {\n let messageTimeoutId = null;\n\n let abortResponse = () => {\n this._abortController.signal.removeEventListener('abort', abortResponse);\n\n clearTimeout(messageTimeoutId);\n this.ws.removeEventListener('message', parseResponse);\n reject({\n type: 'warning',\n id: 17,\n message: 'connection cancelled'\n });\n };\n\n let parseResponse = event => {\n let json = JSON.parse(event.data);\n let r_transaction = json['transaction'];\n\n if (r_transaction === transaction && (!dontResolveOnAck || json['janus'] !== 'ack')) {\n clearTimeout(messageTimeoutId);\n\n this._abortController.signal.removeEventListener('abort', abortResponse);\n\n this.ws.removeEventListener('message', parseResponse);\n\n if (json['janus'] === 'error') {\n var _json$error;\n\n if ((json === null || json === void 0 ? void 0 : (_json$error = json.error) === null || _json$error === void 0 ? void 0 : _json$error.code) == 403) {\n this.disconnect(true);\n }\n\n reject({\n type: 'error',\n id: 2,\n message: 'send failed',\n data: json,\n requestData\n });\n } else {\n resolve(json);\n }\n }\n };\n\n if (ignoreResponse) {\n if (this.ws && this.ws.readyState === 1) {\n this.ws.send(JSON.stringify(requestData));\n }\n\n resolve();\n } else {\n if (this.ws && this.ws.readyState === 1) {\n this.ws.addEventListener('message', parseResponse);\n messageTimeoutId = setTimeout(() => {\n this.ws.removeEventListener('message', parseResponse);\n\n this._abortController.signal.removeEventListener('abort', abortResponse);\n\n reject({\n type: 'error',\n id: 3,\n message: 'send timeout',\n data: requestData\n });\n }, 10000);\n\n this._abortController.signal.addEventListener('abort', abortResponse);\n\n this.ws.send(JSON.stringify(requestData));\n } else {\n reject({\n type: 'warning',\n id: 29,\n message: 'No connection to WebSockets',\n data: requestData\n });\n }\n }\n });\n }\n\n _connectionClosed() {\n if (!this.isConnected || this.isConnecting || this.isDisconnecting) {\n return;\n }\n\n if (this._retries < this._maxRetries) {\n setTimeout(() => {\n this._retries++;\n\n this._reconnect().catch(e => {\n this.emit('error', e);\n });\n }, 3000 * this._retries);\n } else {\n if (this.sessiontype === 'reactooroom') {\n this.disconnect(true);\n } else if (this.sessiontype === 'streaming') {\n this.stopStream();\n }\n\n this.emit('error', {\n type: 'error',\n id: 4,\n message: 'Lost connection to WebSockets',\n data: null\n });\n }\n }\n\n _wipeListeners() {\n if (this.ws) {\n this.ws.removeEventListener('close', this.__connectionClosedBoundFn);\n this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);\n }\n }\n\n _startKeepAlive() {\n this._send({\n \"janus\": \"keepalive\"\n }).then(json => {\n if (json[\"janus\"] !== 'ack') {\n this.emit('error', {\n type: 'warning',\n id: 5,\n message: 'keepalive response suspicious',\n data: json[\"janus\"]\n });\n }\n }).catch(e => {\n this.emit('error', {\n type: 'warning',\n id: 6,\n message: 'keepalive dead',\n data: e\n });\n\n this._connectionClosed();\n });\n\n this._keepAliveId = setTimeout(() => {\n this._startKeepAlive();\n }, 30000);\n }\n\n _stopKeepAlive() {\n clearTimeout(this._keepAliveId);\n }\n\n _handleWsEvents(event) {\n let json = JSON.parse(event.data);\n var sender = json[\"sender\"];\n var type = json[\"janus\"];\n\n let handle = this._getHandle(sender);\n\n if (!handle) {\n return;\n }\n\n if (type === \"trickle\") {\n let candidate = json[\"candidate\"];\n let config = handle.webrtcStuff;\n\n if (config.pc && config.remoteSdp) {\n if (!candidate || candidate.completed === true) {\n config.pc.addIceCandidate(null);\n } else {\n config.pc.addIceCandidate(candidate);\n }\n } else {\n if (!config.candidates) {\n config.candidates = [];\n }\n\n config.candidates.push(candidate);\n }\n } else if (type === \"webrtcup\") {//none universal\n } else if (type === \"hangup\") {\n this._log('hangup on', handle.handleId);\n\n this._removeParticipant(handle.handleId, null, false);\n } else if (type === \"detached\") {\n this._log('detached on', handle.handleId);\n\n this._removeParticipant(handle.handleId, null, true);\n } else if (type === \"media\") {\n this._log('Media event:', handle.handleId, json[\"type\"], json[\"receiving\"], json[\"mid\"]);\n } else if (type === \"slowlink\") {\n this._log('Slowlink', handle.handleId, json[\"uplink\"], json[\"lost\"], json[\"mid\"]);\n } else if (type === \"event\") {//none universal\n } else if (type === 'timeout') {\n this.ws.close(3504, \"Gateway timeout\");\n } else if (type === 'success' || type === 'error') {// we're capturing those elsewhere\n } else {\n this._log(\"Unknown event: \".concat(type, \" on session: \").concat(this.sessionId));\n } // LOCAL\n\n\n if (sender === this.handleId) {\n if (type === \"event\") {\n var plugindata = json[\"plugindata\"] || {};\n var msg = plugindata[\"data\"] || {};\n var jsep = json[\"jsep\"];\n let result = msg[\"result\"] || null;\n let event = msg[\"videoroom\"] || null;\n let list = msg[\"publishers\"] || {};\n let leaving = msg[\"leaving\"]; //let joining = msg[\"joining\"];\n\n let unpublished = msg[\"unpublished\"];\n let error = msg[\"error\"];\n\n if (event === \"joined\") {\n this.id = msg[\"id\"];\n this.privateId = msg[\"private_id\"];\n this.isConnected = true;\n this.emit('joined', true);\n\n this._log('We have successfully joined Room');\n\n for (let f in list) {\n let userId = list[f][\"display\"];\n let streams = list[f][\"streams\"] || [];\n let id = list[f][\"id\"];\n\n for (let i in streams) {\n streams[i][\"id\"] = id;\n streams[i][\"display\"] = userId;\n }\n\n this._log('Remote userId: ', userId);\n\n if (this._participantShouldSubscribe(userId)) {\n this._log('Creating user: ', userId);\n\n this._createParticipant(userId, id).then(handle => {\n return this.sendMessage(handle.handleId, {\n body: {\n \"request\": \"join\",\n \"room\": this.roomId,\n \"ptype\": \"subscriber\",\n \"feed\": id,\n \"private_id\": this.privateId,\n ...(this.webrtcVersion > 1000 ? {\n id: this.userId\n } : {}),\n pin: this.pin\n }\n });\n }).catch(err => {\n this.emit('error', err);\n });\n }\n }\n } else if (event === \"event\") {\n if (msg[\"streams\"] !== undefined && msg[\"streams\"] !== null) {\n this._log('Got my own streams back', msg[\"streams\"]);\n }\n\n for (let f in list) {\n let userId = list[f][\"display\"];\n let streams = list[f][\"streams\"] || [];\n let id = list[f][\"id\"];\n\n for (let i in streams) {\n streams[i][\"id\"] = id;\n streams[i][\"display\"] = userId;\n }\n\n this._log('Remote userId: ', userId);\n\n if (this._participantShouldSubscribe(userId)) {\n this._log('Creating user: ', userId);\n\n this._createParticipant(userId, id).then(handle => {\n return this.sendMessage(handle.handleId, {\n body: {\n \"request\": \"join\",\n \"room\": this.roomId,\n \"ptype\": \"subscriber\",\n \"feed\": id,\n \"private_id\": this.privateId,\n ...(this.webrtcVersion > 1000 ? {\n id: this.userId\n } : {}),\n pin: this.pin\n }\n });\n }).catch(err => {\n this.emit('error', err);\n });\n }\n }\n\n if (leaving === 'ok') {\n this._log('leaving', this.handleId, 'this is us');\n\n this._removeParticipant(this.handleId);\n\n if (msg['reason'] === 'kicked') {\n this.emit('kicked');\n this.disconnect().catch(() => {});\n }\n } else if (leaving) {\n this._log('leaving', leaving);\n\n this._removeParticipant(null, leaving);\n }\n\n if (unpublished === 'ok') {\n this._log('unpublished', this.handleId, 'this is us');\n\n this._removeParticipant(this.handleId, null, false); // we do just hangup\n\n } else if (unpublished) {\n this._log('unpublished', unpublished);\n\n this._removeParticipant(null, unpublished, true); // we do hangup and detach\n\n }\n\n if (error) {\n this.emit('error', {\n type: 'error',\n id: 7,\n message: 'local participant error',\n data: [sender, msg]\n });\n }\n } // Streaming related\n else if (result && result[\"status\"]) {\n this.emit('streamingStatus', result[\"status\"]);\n\n if (result[\"status\"] === 'stopped') {\n this.stopStream();\n }\n\n if (result[\"status\"] === 'started') {\n this.emit('streaming', true);\n this.isStreaming = true;\n }\n }\n\n if (jsep !== undefined && jsep !== null) {\n if (this.sessiontype === 'reactooroom') {\n this._webrtcPeer(this.handleId, jsep).catch(err => {\n this.emit('error', err);\n });\n } else if (this.sessiontype === 'streaming') {\n this._publishRemote(this.handleId, jsep).catch(err => {\n this.emit('error', err);\n });\n }\n }\n } else if (type === \"webrtcup\") {\n this._log('Configuring bitrate: ' + this.initialBitrate);\n\n if (this.initialBitrate > 0) {\n this.sendMessage(this.handleId, {\n \"body\": {\n \"request\": \"configure\",\n \"bitrate\": this.initialBitrate\n }\n }).catch(() => null);\n }\n }\n } //REMOTE\n else {\n let plugindata = json[\"plugindata\"] || {};\n let msg = plugindata[\"data\"] || {};\n let jsep = json[\"jsep\"];\n let event = msg[\"videoroom\"];\n let error = msg[\"error\"];\n\n if (event === \"attached\") {\n var _decodeJanusDisplay3, _decodeJanusDisplay4;\n\n this._log('Remote have successfully joined Room', msg);\n\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: (_decodeJanusDisplay3 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay3 === void 0 ? void 0 : _decodeJanusDisplay3.userId,\n role: (_decodeJanusDisplay4 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay4 === void 0 ? void 0 : _decodeJanusDisplay4.role,\n stream: null,\n track: null,\n adding: false,\n constructId: this.constructId,\n metaData: this.options.metaData,\n hasAudioTrack: false,\n hasVideoTrack: false\n });\n }\n\n if (error) {\n this.emit('error', {\n type: 'warning',\n id: 8,\n message: 'remote participant error',\n data: [sender, msg]\n });\n }\n\n if (jsep) {\n this._publishRemote(handle.handleId, jsep).catch(err => {\n this.emit('error', err);\n });\n }\n }\n }\n\n _handleDataEvents(handleId, type, data) {\n let handle = this._getHandle(handleId);\n\n if (type === 'state') {\n this._log(\" - Data channel status - \", \"UID: \".concat(handleId), \"STATUS: \".concat(JSON.stringify(data)), \"ME: \".concat(handleId === this.handleId));\n\n if (handle) {\n let config = handle.webrtcStuff;\n config.dataChannelOpen = this.defaultDataChannelLabel === (data === null || data === void 0 ? void 0 : data.label) && (data === null || data === void 0 ? void 0 : data.state) === 'open';\n }\n\n if (handleId === this.handleId && this.defaultDataChannelLabel === (data === null || data === void 0 ? void 0 : data.label)) {\n this._isDataChannelOpen = (data === null || data === void 0 ? void 0 : data.state) === 'open';\n this.emit('dataChannel', (data === null || data === void 0 ? void 0 : data.state) === 'open');\n }\n }\n\n if (type === 'error') {\n this.emit('error', {\n type: 'warning',\n id: 9,\n message: 'data event warning',\n data: [handleId, data]\n });\n\n if (handle) {\n let config = handle.webrtcStuff;\n\n if (this.defaultDataChannelLabel === data.label) {\n config.dataChannelOpen = false;\n }\n }\n\n if (handleId === this.handleId && this.defaultDataChannelLabel === data.label) {\n this._isDataChannelOpen = false;\n this.emit('dataChannel', false);\n }\n }\n\n if (handleId === this.handleId && type === 'message') {\n let d = null;\n\n try {\n d = JSON.parse(data);\n } catch (e) {\n this.emit('error', {\n type: 'warning',\n id: 10,\n message: 'data message parse error',\n data: [handleId, e]\n });\n return;\n }\n\n this.emit('data', d);\n }\n } //removeHandle === true -> hangup, detach, removeHandle === false -> hangup\n\n\n _removeParticipant(handleId, rfid) {\n let removeHandle = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n\n let handle = this._getHandle(handleId, rfid);\n\n if (!handle) {\n return Promise.resolve();\n } else {\n handleId = handle.handleId;\n }\n\n return this._send({\n \"janus\": \"hangup\",\n \"handle_id\": handleId\n }, true).then(() => removeHandle ? this._send({\n \"janus\": \"detach\",\n \"handle_id\": handleId\n }, true) : Promise.resolve()).finally(() => {\n try {\n if (handle.webrtcStuff.stream && !this.isRestarting) {\n handle.webrtcStuff.stream.getTracks().forEach(track => track.stop());\n }\n } catch (e) {// Do nothing\n }\n\n handle.webrtcStuff.stream = null;\n\n if (handle.webrtcStuff.dataChannel) {\n Object.keys(handle.webrtcStuff.dataChannel).forEach(label => {\n handle.webrtcStuff.dataChannel[label].onmessage = null;\n handle.webrtcStuff.dataChannel[label].onopen = null;\n handle.webrtcStuff.dataChannel[label].onclose = null;\n handle.webrtcStuff.dataChannel[label].onerror = null;\n });\n }\n\n if (handle.webrtcStuff.pc) {\n handle.webrtcStuff.pc.onicecandidate = null;\n handle.webrtcStuff.pc.ontrack = null;\n handle.webrtcStuff.pc.ondatachannel = null;\n handle.webrtcStuff.pc.onconnectionstatechange = null;\n handle.webrtcStuff.pc.oniceconnectionstatechange = null;\n }\n\n try {\n handle.webrtcStuff.pc.close();\n } catch (e) {}\n\n handle.webrtcStuff = {\n stream: null,\n mySdp: null,\n mediaConstraints: null,\n pc: null,\n dataChannelOpen: false,\n dataChannel: null,\n dtmfSender: null,\n trickle: true,\n iceDone: false\n };\n\n if (handleId === this.handleId) {\n var _decodeJanusDisplay5, _decodeJanusDisplay6;\n\n this._isDataChannelOpen = false;\n this.isPublished = false;\n this.emit('published', {\n status: false,\n hasStream: false\n });\n this.emit('removeLocalParticipant', {\n id: handleId,\n userId: (_decodeJanusDisplay5 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay5 === void 0 ? void 0 : _decodeJanusDisplay5.userId,\n role: (_decodeJanusDisplay6 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay6 === void 0 ? void 0 : _decodeJanusDisplay6.role\n });\n } else {\n var _decodeJanusDisplay7, _decodeJanusDisplay8;\n\n this.emit(this._getRemoveParticipantEventName(handleId), {\n id: handleId,\n userId: (_decodeJanusDisplay7 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay7 === void 0 ? void 0 : _decodeJanusDisplay7.userId,\n role: (_decodeJanusDisplay8 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay8 === void 0 ? void 0 : _decodeJanusDisplay8.role\n });\n }\n\n if (removeHandle) {\n let handleIndex = this._participants.findIndex(p => p.handleId === handleId);\n\n this._participants.splice(handleIndex, 1);\n }\n\n return true;\n });\n }\n\n _createParticipant() {\n let userId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let rfid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n return this._send({\n \"janus\": \"attach\",\n \"plugin\": this.pluginName\n }).then(json => {\n let handleId = json.data[\"id\"];\n let handle = {\n handleId,\n rfid,\n userId,\n webrtcStuff: {\n stream: null,\n mySdp: null,\n mediaConstraints: null,\n pc: null,\n dataChannelOpen: false,\n dataChannel: null,\n dtmfSender: null,\n trickle: true,\n iceDone: false,\n isIceRestarting: false\n }\n };\n\n this._participants.push(handle);\n\n return handle;\n });\n }\n\n _joinRoom(roomId, pin, userId, display) {\n return this.sendMessage(this.handleId, {\n body: {\n \"request\": \"join\",\n \"room\": roomId,\n \"pin\": pin,\n \"ptype\": \"publisher\",\n \"display\": display,\n ...(this.webrtcVersion > 1000 ? {\n id: userId\n } : {})\n }\n }, false, true);\n }\n\n _watchStream(id) {\n return this.sendMessage(this.handleId, {\n body: {\n \"request\": \"watch\",\n id: parseInt(id)\n }\n }, false, true);\n }\n\n _leaveRoom() {\n let dontWait = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n return this.isConnected ? this.sendMessage(this.handleId, {\n body: {\n \"request\": \"leave\"\n }\n }, dontWait).finally(() => {\n this.isConnected = false;\n this.emit('joined', false);\n }) : Promise.resolve();\n } // internal reconnect\n\n\n _reconnect() {\n if (this.isReclaiming) {\n return Promise.resolve();\n }\n\n if (this.ws) {\n this._wipeListeners();\n\n if (this.ws.readyState === 1) {\n this.ws.close();\n }\n }\n\n this._stopKeepAlive();\n\n this.isReclaiming = true;\n this.emit('joining', true);\n return new Promise((resolve, reject) => {\n let abortReconnect = () => {\n this._abortController.signal.removeEventListener('abort', abortReconnect);\n\n this.ws.removeEventListener('close', this.__connectionClosedBoundFn);\n this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);\n this.ws.onopen = null;\n this.ws.onerror = null;\n this.isReclaiming = false;\n this.emit('joining', false);\n reject({\n type: 'warning',\n id: 17,\n message: 'Connection cancelled',\n data: e\n });\n };\n\n this.ws = new WebSocket(this.server, 'janus-protocol');\n this.__connectionClosedBoundFn = this._connectionClosed.bind(this);\n this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);\n this.ws.addEventListener('close', this.__connectionClosedBoundFn);\n this.ws.addEventListener('message', this.__handleWsEventsBoundFn);\n\n this.ws.onopen = () => {\n this._abortController.signal.removeEventListener('abort', abortReconnect);\n\n this._send({\n \"janus\": \"claim\"\n }).then(json => {\n this.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n this._startKeepAlive();\n\n this.isReclaiming = false;\n this.emit('joining', false);\n this._retries = 0;\n resolve(json);\n }).catch(error => {\n this.isReclaiming = false;\n this.emit('joining', false);\n reject({\n type: 'error',\n id: 11,\n message: 'reconnection error',\n data: error\n });\n });\n }; // this is called before 'close' event callback so it doesn't break reconnect loop\n\n\n this.ws.onerror = e => {\n this._abortController.signal.removeEventListener('abort', abortReconnect);\n\n this.isReclaiming = false;\n this.emit('joining', false);\n reject({\n type: 'warning',\n id: 12,\n message: 'ws reconnection error',\n data: e\n });\n };\n\n this._abortController.signal.addEventListener('abort', abortReconnect);\n });\n }\n\n connect(roomId, pin, server, iceServers, token, display, userId) {\n let webrtcVersion = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 0;\n let initialBitrate = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : 0;\n let recordingFilename = arguments.length > 9 ? arguments[9] : undefined;\n\n if (this.isConnecting) {\n return Promise.reject({\n type: 'warning',\n id: 16,\n message: 'connection already in progress'\n });\n }\n\n if (this.ws) {\n this._wipeListeners();\n }\n\n this._stopKeepAlive();\n\n this._abortController = new AbortController();\n this.sessionId = null;\n this.server = server;\n this.iceServers = iceServers;\n this.token = token;\n this.roomId = roomId;\n this.pin = pin;\n this.display = display;\n this.userId = userId;\n this.webrtcVersion = webrtcVersion;\n this.initialBitrate = initialBitrate;\n this.recordingFilename = recordingFilename;\n this.isConnecting = true;\n this.emit('joining', true);\n return new Promise((resolve, reject) => {\n this.ws = new WebSocket(this.server, 'janus-protocol');\n this.__connectionClosedBoundFn = this._connectionClosed.bind(this);\n this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);\n\n let abortConnect = () => {\n this._abortController.signal.removeEventListener('abort', abortConnect);\n\n this.ws.removeEventListener('close', this.__connectionClosedBoundFn);\n this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);\n this.ws.onopen = null;\n this.ws.onerror = null;\n this.isConnecting = false;\n this.emit('joining', false);\n reject({\n type: 'warning',\n id: 17,\n message: 'Connection cancelled'\n });\n };\n\n this.ws.addEventListener('close', this.__connectionClosedBoundFn);\n this.ws.addEventListener('message', this.__handleWsEventsBoundFn);\n\n this.ws.onopen = () => {\n this._abortController.signal.removeEventListener('abort', abortConnect);\n\n this._retries = 0;\n\n this._send({\n \"janus\": \"create\"\n }).then(json => {\n this.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n this._startKeepAlive();\n\n return 1;\n }).then(() => this._createParticipant(userId)).then(handle => {\n this.handleId = handle.handleId;\n return 1;\n }).then(() => this._joinRoom(roomId, pin, userId, display)).then(() => {\n this.isConnecting = false;\n this.emit('joining', false);\n resolve(this);\n }).catch(error => {\n this.isConnecting = false;\n this.emit('joining', false);\n reject({\n type: (error === null || error === void 0 ? void 0 : error.type) === 'warning' ? 'warning' : 'error',\n id: 13,\n message: 'connection error',\n data: error\n });\n });\n };\n\n this.ws.onerror = e => {\n this._abortController.signal.removeEventListener('abort', abortConnect);\n\n this.isConnecting = false;\n this.emit('joining', false);\n reject({\n type: 'error',\n id: 14,\n message: 'ws connection error',\n data: e\n });\n };\n\n this._abortController.signal.addEventListener('abort', abortConnect);\n });\n }\n\n disconnect() {\n var _this$_abortControlle, _this$_abortControlle2;\n\n if (this.isDisconnecting) {\n return Promise.resolve();\n }\n\n (_this$_abortControlle = this._abortController) === null || _this$_abortControlle === void 0 ? void 0 : (_this$_abortControlle2 = _this$_abortControlle.abort) === null || _this$_abortControlle2 === void 0 ? void 0 : _this$_abortControlle2.call(_this$_abortControlle);\n\n this._stopKeepAlive();\n\n let isConnected = this.isConnected;\n this.isDisconnecting = true;\n return Promise.all(this._participants.map(p => this._removeParticipant(p.handleId))).finally(() => {\n this._wipeListeners();\n\n if (this.ws && this.ws.readyState === 1) {\n this._send({\n \"janus\": \"destroy\"\n }, true);\n\n this.ws.close();\n }\n\n this.sessionId = null;\n this.isPublished = false;\n this.isConnected = false;\n this.isDisconnecting = false;\n this.emit('publishing', false);\n this.emit('published', {\n status: false,\n hasStream: false\n });\n this.emit('joining', false);\n this.emit('joined', false);\n this.emit('disconnect', isConnected);\n return Promise.resolve('Disconnected');\n });\n }\n\n startStream(streamId, server, iceServers, token, userId) {\n if (this.isConnecting) {\n return Promise.reject({\n type: 'warning',\n id: 16,\n message: 'connection error',\n data: 'Connection is in progress'\n });\n }\n\n if (this.ws) {\n this._wipeListeners();\n }\n\n this._stopKeepAlive();\n\n this._abortController = new AbortController();\n this.server = server;\n this.iceServers = iceServers;\n this.token = token;\n this.streamId = streamId;\n this.userId = userId;\n this.sessionId = null;\n this.isConnecting = true;\n this.emit('streamStarting', true);\n return new Promise((resolve, reject) => {\n this.ws = new WebSocket(this.server, 'janus-protocol');\n this.__connectionClosedBoundFn = this._connectionClosed.bind(this);\n this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);\n\n let abortConnect = () => {\n this._abortController.signal.removeEventListener('abort', abortConnect);\n\n this.ws.removeEventListener('close', this.__connectionClosedBoundFn);\n this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);\n this.ws.onopen = null;\n this.ws.onerror = null;\n this.isConnecting = false;\n this.emit('streamStarting', false);\n reject({\n type: 'warning',\n id: 17,\n message: 'Connection cancelled'\n });\n };\n\n this.ws.addEventListener('close', this.__connectionClosedBoundFn);\n this.ws.addEventListener('message', this.__handleWsEventsBoundFn);\n\n this.ws.onopen = () => {\n this._abortController.signal.removeEventListener('abort', abortConnect);\n\n this._retries = 0;\n\n this._send({\n \"janus\": \"create\"\n }).then(json => {\n this.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n this._startKeepAlive();\n\n return 1;\n }).then(() => this._createParticipant(userId)).then(handle => {\n this.handleId = handle.handleId;\n return 1;\n }).then(() => this._watchStream(streamId)).then(() => {\n this.isConnecting = false;\n this.emit('streamStarting', false);\n resolve(this);\n }).catch(error => {\n this.isConnecting = false;\n this.emit('streamStarting', false);\n reject({\n type: 'error',\n id: 13,\n message: 'connection error',\n data: error\n });\n });\n };\n\n this.ws.onerror = e => {\n this._abortController.signal.removeEventListener('abort', abortConnect);\n\n this.isConnecting = false;\n this.emit('streamStarting', false);\n reject({\n type: 'error',\n id: 14,\n message: 'ws connection error',\n data: e\n });\n };\n\n this._abortController.signal.addEventListener('abort', abortConnect);\n });\n }\n\n stopStream() {\n var _this$_abortControlle3, _this$_abortControlle4;\n\n if (this.isDisconnecting) {\n return Promise.resolve();\n }\n\n (_this$_abortControlle3 = this._abortController) === null || _this$_abortControlle3 === void 0 ? void 0 : (_this$_abortControlle4 = _this$_abortControlle3.abort) === null || _this$_abortControlle4 === void 0 ? void 0 : _this$_abortControlle4.call(_this$_abortControlle3);\n\n this._stopKeepAlive();\n\n let isStreaming = this.isStreaming;\n this.isDisconnecting = true;\n return this.sendMessage(this.handleId, {\n body: {\n \"request\": \"stop\"\n }\n }, false, true).then(() => this._removeParticipant(this.handleId)).finally(() => {\n this._wipeListeners();\n\n this._send({\n \"janus\": \"destroy\"\n }, true);\n\n if (this.ws && this.ws.readyState === 1) {\n this.ws.close();\n }\n\n this.sessionId = null;\n this.isDisconnecting = false;\n this.isStreaming = false;\n this.emit('streamStarting', false);\n this.emit('streaming', false);\n this.emit('disconnect', isStreaming);\n return Promise.resolve('Disconnected');\n });\n }\n\n destroy() {\n if (this.sessiontype === 'reactooroom') {\n return this.disconnect().then(() => {\n this.clear();\n return true;\n });\n } else if (this.sessiontype === 'streaming') {\n return this.stopStream().then(() => {\n this.clear();\n return true;\n });\n }\n }\n\n _enableDebug() {\n this._log = console.log.bind(console);\n }\n\n _getHandle(handleId) {\n let rfid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n return this._participants.find(p => p.handleId === handleId || rfid && p.rfid === rfid);\n }\n\n _getStats() {\n let type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n return Promise.all(this._participants.map(participant => {\n let mediaTrack = null;\n\n if (type === 'video') {\n mediaTrack = participant.webrtcStuff && participant.webrtcStuff.stream && participant.webrtcStuff.stream.getVideoTracks().length && participant.webrtcStuff.stream.getVideoTracks()[0];\n } else if (type === 'audio') {\n mediaTrack = participant.webrtcStuff && participant.webrtcStuff.stream && participant.webrtcStuff.stream.getAudioTracks().length && participant.webrtcStuff.stream.getAudioTracks()[0];\n }\n\n return participant.webrtcStuff && participant.webrtcStuff.pc && participant.webrtcStuff.pc.getStats(mediaTrack).then(r => ({\n handle: participant,\n stats: r\n })).catch(e => Promise.resolve({\n handle: participant,\n stats: e\n }));\n }));\n }\n\n _sendTrickleCandidate(handleId, candidate) {\n return this._send({\n \"janus\": \"trickle\",\n \"candidate\": candidate,\n \"handle_id\": handleId\n });\n }\n\n _webrtc(handleId) {\n let enableOntrack = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n this.emit('error', {\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'create rtc connection']\n });\n }\n\n let config = handle.webrtcStuff;\n\n if (!config.pc) {\n let pc_config = {\n \"iceServers\": this.iceServers,\n \"iceTransportPolicy\": 'all',\n \"bundlePolicy\": undefined\n };\n pc_config[\"sdpSemantics\"] = this.isUnifiedPlan ? \"unified-plan\" : \"plan-b\";\n let pc_constraints = {\n \"optional\": [{\n \"DtlsSrtpKeyAgreement\": true\n }]\n };\n\n if (this._ipv6Support === true) {\n pc_constraints.optional.push({\n \"googIPv6\": true\n });\n }\n\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === \"edge\") {\n // This is Edge, enable BUNDLE explicitly\n pc_config.bundlePolicy = \"max-bundle\";\n }\n\n this._log('new RTCPeerConnection', pc_config, pc_constraints);\n\n config.pc = new RTCPeerConnection(pc_config, pc_constraints);\n\n config.pc.onconnectionstatechange = () => {\n if (config.pc.connectionState === 'failed') {\n this._iceRestart(handleId);\n }\n\n this.emit('connectionState', [handleId, handleId === this.handleId, config.pc.connectionState]);\n\n if (handleId !== this.handleId && config.pc.connectionState === 'connected') {\n var _decodeJanusDisplay9, _decodeJanusDisplay10;\n\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: (_decodeJanusDisplay9 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay9 === void 0 ? void 0 : _decodeJanusDisplay9.userId,\n role: (_decodeJanusDisplay10 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay10 === void 0 ? void 0 : _decodeJanusDisplay10.role,\n stream: config.stream,\n track: null,\n optional: true,\n constructId: this.constructId,\n metaData: this.options.metaData,\n adding: false,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n }\n };\n\n config.pc.oniceconnectionstatechange = () => {\n if (config.pc.iceConnectionState === 'failed') {\n this._iceRestart(handleId);\n }\n\n this.emit('iceState', [handleId, handleId === this.handleId, config.pc.iceConnectionState]);\n\n if (handleId !== this.handleId && (config.pc.iceConnectionState === 'completed' || config.pc.iceConnectionState === 'connected')) {\n var _decodeJanusDisplay11, _decodeJanusDisplay12;\n\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: (_decodeJanusDisplay11 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay11 === void 0 ? void 0 : _decodeJanusDisplay11.userId,\n role: (_decodeJanusDisplay12 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay12 === void 0 ? void 0 : _decodeJanusDisplay12.role,\n stream: config.stream,\n track: null,\n optional: true,\n constructId: this.constructId,\n metaData: this.options.metaData,\n adding: false,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n }\n };\n\n config.pc.onicecandidate = event => {\n if (event.candidate == null || webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'edge' && event.candidate.candidate.indexOf('endOfCandidates') > 0) {\n config.iceDone = true;\n\n this._sendTrickleCandidate(handleId, {\n \"completed\": true\n }).catch(e => {\n this.emit('error', e);\n });\n } else {\n // JSON.stringify doesn't work on some WebRTC objects anymore\n // See https://code.google.com/p/chromium/issues/detail?id=467366\n var candidate = {\n \"candidate\": event.candidate.candidate,\n \"sdpMid\": event.candidate.sdpMid,\n \"sdpMLineIndex\": event.candidate.sdpMLineIndex\n };\n\n this._sendTrickleCandidate(handleId, candidate).catch(e => {\n this.emit('error', e);\n });\n }\n };\n\n if (enableOntrack) {\n config.pc.ontrack = event => {\n if (!event.streams) return; //config.stream = event.streams[0];\n\n if (!config.stream) {\n config.stream = new MediaStream();\n }\n\n if (event.track) {\n var _decodeJanusDisplay13, _decodeJanusDisplay14;\n\n let mid = event.transceiver ? event.transceiver.mid : event.track.id;\n config.stream.addTrack(event.track);\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n mid,\n id: handle.handleId,\n userId: (_decodeJanusDisplay13 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay13 === void 0 ? void 0 : _decodeJanusDisplay13.userId,\n role: (_decodeJanusDisplay14 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay14 === void 0 ? void 0 : _decodeJanusDisplay14.role,\n stream: config.stream,\n track: event.track,\n constructId: this.constructId,\n metaData: this.options.metaData,\n adding: true,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n if (event.track.onended) return;\n\n event.track.onended = ev => {\n let mid = ev.target.id;\n\n if (this.isUnifiedPlan) {\n let transceiver = config.pc.getTransceivers().find(t => t.receiver.track === ev.target);\n mid = transceiver.mid;\n }\n\n if (config.stream) {\n var _decodeJanusDisplay15, _decodeJanusDisplay16;\n\n config.stream && config.stream.removeTrack(ev.target);\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n mid,\n userId: (_decodeJanusDisplay15 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay15 === void 0 ? void 0 : _decodeJanusDisplay15.userId,\n role: (_decodeJanusDisplay16 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay16 === void 0 ? void 0 : _decodeJanusDisplay16.role,\n stream: config.stream,\n track: ev.target,\n constructId: this.constructId,\n metaData: this.options.metaData,\n adding: false,\n removing: true,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n }\n };\n\n event.track.onmute = ev => {\n var _decodeJanusDisplay17, _decodeJanusDisplay18;\n\n this._log('remoteTrackMuted', 'onmute');\n\n let mid = ev.target.id;\n\n if (this.isUnifiedPlan) {\n let transceiver = config.pc.getTransceivers().find(t => t.receiver.track === ev.target);\n mid = transceiver.mid;\n }\n\n this.emit('remoteTrackMuted', {\n id: handle.handleId,\n mid,\n userId: (_decodeJanusDisplay17 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay17 === void 0 ? void 0 : _decodeJanusDisplay17.userId,\n role: (_decodeJanusDisplay18 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay18 === void 0 ? void 0 : _decodeJanusDisplay18.role,\n stream: config.stream,\n kind: ev.target.kind,\n track: ev.target,\n muted: true\n });\n };\n\n event.track.onunmute = ev => {\n var _decodeJanusDisplay19, _decodeJanusDisplay20;\n\n this._log('remoteTrackMuted', 'onunmute');\n\n let mid = ev.target.id;\n\n if (this.isUnifiedPlan) {\n let transceiver = config.pc.getTransceivers().find(t => t.receiver.track === ev.target);\n mid = transceiver.mid;\n }\n\n this.emit('remoteTrackMuted', {\n id: handle.handleId,\n mid,\n userId: (_decodeJanusDisplay19 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay19 === void 0 ? void 0 : _decodeJanusDisplay19.userId,\n role: (_decodeJanusDisplay20 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay20 === void 0 ? void 0 : _decodeJanusDisplay20.role,\n stream: config.stream,\n kind: ev.target.kind,\n track: ev.target,\n muted: false\n });\n };\n }\n };\n }\n }\n\n if (!config.dataChannel || !config.dataChannelOpen) {\n config.dataChannel = {};\n\n var onDataChannelMessage = event => {\n this._handleDataEvents(handleId, 'message', event.data);\n };\n\n var onDataChannelStateChange = event => {\n let label = event.target.label;\n let protocol = event.target.protocol;\n let state = config.dataChannel[label] ? config.dataChannel[label].readyState : \"null\";\n\n this._handleDataEvents(handleId, 'state', {\n state,\n label\n });\n }; //TODO: check this\n\n\n var onDataChannelError = error => {\n var _error$channel;\n\n this._handleDataEvents(handleId, 'error', {\n label: error === null || error === void 0 ? void 0 : (_error$channel = error.channel) === null || _error$channel === void 0 ? void 0 : _error$channel.label,\n error\n });\n };\n\n const createDataChannel = (label, protocol, incoming) => {\n let options = {\n ordered: true\n };\n\n if (!incoming) {\n if (protocol) {\n options = { ...options,\n protocol\n };\n }\n\n config.dataChannel[label] = config.pc.createDataChannel(label, options);\n } else {\n config.dataChannel[label] = incoming;\n }\n\n config.dataChannel[label].onmessage = onDataChannelMessage;\n config.dataChannel[label].onopen = onDataChannelStateChange;\n config.dataChannel[label].onclose = onDataChannelStateChange;\n config.dataChannel[label].onerror = onDataChannelError;\n };\n\n createDataChannel(this.defaultDataChannelLabel, null, null);\n\n config.pc.ondatachannel = function (event) {\n createDataChannel(event.channel.label, event.channel.protocol, event.channel);\n };\n }\n }\n\n _webrtcPeer(handleId, jsep) {\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'rtc peer']\n });\n }\n\n var config = handle.webrtcStuff;\n\n if (jsep !== undefined && jsep !== null) {\n if (config.pc === null) {\n this._log(\"No PeerConnection: if this is an answer, use createAnswer and not _webrtcPeer\");\n\n return Promise.resolve(null);\n }\n\n return config.pc.setRemoteDescription(jsep).then(() => {\n config.remoteSdp = jsep.sdp; // Any trickle candidate we cached?\n\n if (config.candidates && config.candidates.length > 0) {\n for (var i = 0; i < config.candidates.length; i++) {\n var candidate = config.candidates[i];\n\n if (!candidate || candidate.completed === true) {\n config.pc.addIceCandidate(null);\n } else {\n config.pc.addIceCandidate(candidate);\n }\n }\n\n config.candidates = [];\n } // Done\n\n\n return true;\n });\n } else {\n return Promise.reject({\n type: 'warning',\n id: 22,\n message: 'rtc peer',\n data: [handleId, 'invalid jsep']\n });\n }\n }\n\n _iceRestart(handleId) {\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n return;\n }\n\n var config = handle.webrtcStuff; // Already restarting;\n\n if (config.isIceRestarting) {\n return;\n }\n\n if (this.handleId === handleId) {\n this._log('Performing local ICE restart');\n\n config.isIceRestarting = true;\n let hasAudio = !!(config.stream && config.stream.getAudioTracks().length > 0);\n let hasVideo = !!(config.stream && config.stream.getVideoTracks().length > 0);\n\n this._createAO('offer', handleId, true, [hasAudio, false, hasVideo, false]).then(jsep => {\n if (!jsep) {\n return null;\n }\n\n return this.sendMessage(handleId, {\n body: {\n \"request\": \"configure\",\n \"audio\": hasAudio,\n \"video\": hasVideo,\n \"data\": true,\n ...(this.recordingFilename ? {\n filename: this.recordingFilename\n } : {})\n },\n jsep\n });\n }).then(r => {\n config.isIceRestarting = false;\n\n this._log('ICE restart success');\n }).catch(e => {\n config.isIceRestarting = false;\n this.emit('warning', {\n type: 'error',\n id: 28,\n message: 'iceRestart failed',\n data: e\n });\n });\n } else {\n this._log('Performing remote ICE restart', handleId);\n\n config.isIceRestarting = true;\n return this.sendMessage(handleId, {\n body: {\n \"request\": \"configure\",\n \"restart\": true\n }\n }).then(() => {\n config.isIceRestarting = false;\n }).catch(() => {\n config.isIceRestarting = false;\n });\n }\n }\n\n _createAO() {\n let type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'offer';\n let handleId = arguments.length > 1 ? arguments[1] : undefined;\n let iceRestart = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n let [audioSend, audioRecv, videoSend, videoRecv] = arguments.length > 3 ? arguments[3] : undefined;\n\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'createAO', type]\n });\n }\n\n let methodName = null;\n\n if (type === 'offer') {\n methodName = 'createOffer';\n } else {\n methodName = 'createAnswer';\n }\n\n var config = handle.webrtcStuff; // https://code.google.com/p/webrtc/issues/detail?id=3508\n\n var mediaConstraints = {};\n\n if (this.isUnifiedPlan) {\n var audioTransceiver = null,\n videoTransceiver = null;\n var transceivers = config.pc.getTransceivers();\n\n if (transceivers && transceivers.length > 0) {\n for (var i in transceivers) {\n var t = transceivers[i];\n\n if (t.sender && t.sender.track && t.sender.track.kind === \"audio\" && t.stopped === false || t.receiver && t.receiver.track && t.receiver.track.kind === \"audio\" && t.stopped === false) {\n if (!audioTransceiver) audioTransceiver = t;\n continue;\n }\n\n if (t.sender && t.sender.track && t.sender.track.kind === \"video\" && t.stopped === false || t.receiver && t.receiver.track && t.receiver.track.kind === \"video\" && t.stopped === false) {\n if (!videoTransceiver) videoTransceiver = t;\n continue;\n }\n }\n } // Handle audio (and related changes, if any)\n\n\n if (!audioSend && !audioRecv) {\n // Audio disabled: have we removed it?\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"inactive\");\n } else {\n audioTransceiver.direction = \"inactive\";\n }\n }\n } else {\n // Take care of audio m-line\n if (audioSend && audioRecv) {\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"sendrecv\");\n } else {\n audioTransceiver.direction = \"sendrecv\";\n }\n }\n } else if (audioSend && !audioRecv) {\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"sendonly\");\n } else {\n audioTransceiver.direction = \"sendonly\";\n }\n }\n } else if (!audioSend && audioRecv) {\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"recvonly\");\n } else {\n audioTransceiver.direction = \"recvonly\";\n }\n } else {\n // In theory, this is the only case where we might not have a transceiver yet\n audioTransceiver = config.pc.addTransceiver(\"audio\", {\n direction: \"recvonly\"\n });\n }\n }\n } // Handle video (and related changes, if any)\n\n\n if (!videoSend && !videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"inactive\");\n } else {\n videoTransceiver.direction = \"inactive\";\n }\n }\n } else {\n // Take care of video m-line\n if (videoSend && videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"sendrecv\");\n } else {\n videoTransceiver.direction = \"sendrecv\";\n }\n }\n } else if (videoSend && !videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"sendonly\");\n } else {\n videoTransceiver.direction = \"sendonly\";\n }\n }\n } else if (!videoSend && videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"recvonly\");\n } else {\n videoTransceiver.direction = \"recvonly\";\n }\n } else {\n // In theory, this is the only case where we might not have a transceiver yet\n videoTransceiver = config.pc.addTransceiver(\"video\", {\n direction: \"recvonly\"\n });\n }\n }\n }\n } else {\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === \"firefox\" || webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === \"edge\") {\n mediaConstraints = {\n offerToReceiveAudio: audioRecv,\n offerToReceiveVideo: videoRecv\n };\n } else {\n mediaConstraints = {\n mandatory: {\n OfferToReceiveAudio: audioRecv,\n OfferToReceiveVideo: videoRecv\n }\n };\n }\n }\n\n if (iceRestart) {\n mediaConstraints[\"iceRestart\"] = true;\n }\n\n return config.pc[methodName](mediaConstraints).then(function (response) {\n config.mySdp = response.sdp;\n\n let _p = config.pc.setLocalDescription(response).catch(e => {\n return Promise.reject({\n type: 'warning',\n id: 24,\n message: 'setLocalDescription',\n data: [handleId, e]\n });\n });\n\n config.mediaConstraints = mediaConstraints;\n\n if (!config.iceDone && !config.trickle) {\n // Don't do anything until we have all candidates\n return Promise.resolve(null);\n } // JSON.stringify doesn't work on some WebRTC objects anymore\n // See https://code.google.com/p/chromium/issues/detail?id=467366\n\n\n var jsep = {\n \"type\": response.type,\n \"sdp\": response.sdp\n };\n return _p.then(() => jsep);\n }, e => {\n return Promise.reject({\n type: 'warning',\n id: 25,\n message: methodName,\n data: [handleId, e]\n });\n });\n }\n\n _publishRemote(handleId, jsep) {\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'publish remote participant']\n });\n }\n\n this._webrtc(handleId, true);\n\n let config = handle.webrtcStuff;\n\n if (jsep) {\n return config.pc.setRemoteDescription(jsep).then(() => {\n config.remoteSdp = jsep.sdp; // Any trickle candidate we cached?\n\n if (config.candidates && config.candidates.length > 0) {\n for (var i = 0; i < config.candidates.length; i++) {\n var candidate = config.candidates[i];\n\n if (!candidate || candidate.completed === true) {\n // end-of-candidates\n config.pc.addIceCandidate(null);\n } else {\n // New candidate\n config.pc.addIceCandidate(candidate);\n }\n }\n\n config.candidates = [];\n } // Create the answer now\n\n\n return this._createAO('answer', handleId, false, [false, true, false, true]).then(_jsep => {\n if (!_jsep) {\n this.emit('error', {\n type: 'warning',\n id: 19,\n message: 'publish remote participant',\n data: [handleId, 'no jsep']\n });\n return Promise.resolve();\n }\n\n return this.sendMessage(handleId, {\n \"body\": {\n \"request\": \"start\",\n ...(this.roomId && {\n \"room\": this.roomId\n }),\n ...(this.pin && {\n pin: this.pin\n })\n },\n \"jsep\": _jsep\n });\n });\n }, e => Promise.reject({\n type: 'warning',\n id: 23,\n message: 'setRemoteDescription',\n data: [handleId, e]\n }));\n } else {\n return Promise.resolve();\n }\n } //Public methods\n\n\n publishLocal(stream) {\n let {\n keepAudio = false,\n keepVideo = false\n } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n if (this.isDisconnecting || !this.isConnected) {\n return Promise.reject({\n type: 'warning',\n id: 18,\n message: 'Either not connected or disconnecting'\n });\n }\n\n this.emit('publishing', true);\n\n let handle = this._getHandle(this.handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'error',\n id: 21,\n message: 'no local id, connect before publishing',\n data: null\n });\n }\n\n this._webrtc(this.handleId);\n\n let config = handle.webrtcStuff;\n\n if (stream) {\n if (!config.stream) {\n config.stream = stream;\n stream.getTracks().forEach(function (track) {\n config.pc.addTrack(track, stream);\n });\n } else {\n /* UPDATE Audio */\n let replaceAudio = stream.getAudioTracks().length;\n\n if (replaceAudio || !keepAudio) {\n //this will stop existing tracks\n let oldAudioStream = config.stream.getAudioTracks()[0];\n\n if (oldAudioStream) {\n config.stream.removeTrack(oldAudioStream);\n\n try {\n oldAudioStream.stop();\n } catch (e) {\n this._log(e);\n }\n }\n }\n\n if (config.pc.getSenders() && config.pc.getSenders().length) {\n if (replaceAudio && this.isUnifiedPlan) {//using replace\n } else {\n for (let index in config.pc.getSenders()) {\n let s = config.pc.getSenders()[index];\n\n if (s && s.track && s.track.kind === \"audio\") {\n config.pc.removeTrack(s);\n }\n }\n }\n }\n\n if (replaceAudio) {\n config.stream.addTrack(stream.getAudioTracks()[0]);\n var audioTransceiver = null;\n\n if (this.isUnifiedPlan) {\n let transceivers = config.pc.getTransceivers();\n\n if (transceivers && transceivers.length > 0) {\n for (let i in transceivers) {\n let t = transceivers[i];\n\n if (t.sender && t.sender.track && t.sender.track.kind === \"audio\" && t.stopped === false || t.receiver && t.receiver.track && t.receiver.track.kind === \"audio\" && t.stopped === false) {\n audioTransceiver = t;\n break;\n }\n }\n }\n }\n\n if (audioTransceiver && audioTransceiver.sender) {\n audioTransceiver.sender.replaceTrack(stream.getAudioTracks()[0]);\n } else {\n config.pc.addTrack(stream.getAudioTracks()[0], stream);\n }\n }\n /* UPDATE Video */\n\n\n let replaceVideo = stream.getVideoTracks().length;\n\n if (replaceVideo || !keepVideo) {\n let oldVideoStream = config.stream.getVideoTracks()[0];\n\n if (oldVideoStream) {\n config.stream.removeTrack(oldVideoStream);\n\n try {\n oldVideoStream.stop();\n } catch (e) {\n this._log(e);\n }\n }\n }\n\n if (config.pc.getSenders() && config.pc.getSenders().length) {\n if (replaceVideo && this.isUnifiedPlan) {//using replace\n } else {\n for (let index in config.pc.getSenders()) {\n let s = config.pc.getSenders()[index];\n\n if (s && s.track && s.track.kind === \"video\") {\n config.pc.removeTrack(s);\n }\n }\n }\n }\n\n if (replaceVideo) {\n config.stream.addTrack(stream.getVideoTracks()[0]);\n var videoTransceiver = null;\n\n if (this.isUnifiedPlan) {\n let transceivers = config.pc.getTransceivers();\n\n if (transceivers && transceivers.length > 0) {\n for (let i in transceivers) {\n let t = transceivers[i];\n\n if (t.sender && t.sender.track && t.sender.track.kind === \"video\" && t.stopped === false || t.receiver && t.receiver.track && t.receiver.track.kind === \"video\" && t.stopped === false) {\n videoTransceiver = t;\n break;\n }\n }\n }\n }\n\n if (videoTransceiver && videoTransceiver.sender) {\n //TODO: check if t.stopped === false still gets us videoTransceiver\n videoTransceiver.sender.replaceTrack(stream.getVideoTracks()[0]);\n } else {\n config.pc.addTrack(stream.getVideoTracks()[0], stream);\n }\n }\n }\n }\n\n let hasAudio = !!(stream && stream.getAudioTracks().length > 0);\n let hasVideo = !!(stream && stream.getVideoTracks().length > 0);\n let isAudioMuted = !stream || stream.getAudioTracks().length === 0 || !stream.getAudioTracks()[0].enabled;\n let isVideoMuted = !stream || stream.getVideoTracks().length === 0 || !stream.getVideoTracks()[0].enabled;\n this.isAudioEnabed = hasAudio;\n this.isVideoEnabled = hasVideo;\n this.isAudioMuted = isAudioMuted;\n this.isVideoMuted = isVideoMuted;\n return this._createAO('offer', this.handleId, false, [hasAudio, false, hasVideo, false]).then(jsep => {\n if (!jsep) {\n return null;\n } //HOTFIX: Temporary fix for Safari 13\n\n\n if (jsep.sdp && jsep.sdp.indexOf(\"\\r\\na=ice-ufrag\") === -1) {\n jsep.sdp = jsep.sdp.replace(\"\\na=ice-ufrag\", \"\\r\\na=ice-ufrag\");\n }\n\n return this.sendMessage(this.handleId, {\n body: {\n \"request\": \"configure\",\n \"audio\": hasAudio,\n \"video\": hasVideo,\n \"data\": true,\n ...(this.recordingFilename ? {\n filename: this.recordingFilename\n } : {})\n },\n jsep\n });\n }).then(r => {\n if (this._isDataChannelOpen) {\n return Promise.resolve(r);\n } else {\n return new Promise((resolve, reject) => {\n let dataChannelTimeoutId = null;\n\n let _resolve = val => {\n if (val) {\n clearTimeout(dataChannelTimeoutId);\n\n this._abortController.signal.removeEventListener('abort', _rejectAbort);\n\n this.off('dataChannel', _resolve, this);\n resolve(this);\n }\n };\n\n let _rejectTimeout = () => {\n this.off('dataChannel', _resolve, this);\n\n this._abortController.signal.removeEventListener('abort', _rejectAbort);\n\n reject({\n type: 'error',\n id: 27,\n message: 'Data channel did not open',\n data: null\n });\n };\n\n let _rejectAbort = () => {\n this._abortController.signal.removeEventListener('abort', _rejectAbort);\n\n clearTimeout(dataChannelTimeoutId);\n this.off('dataChannel', _resolve, this);\n reject({\n type: 'warning',\n id: 17,\n message: 'Connection cancelled'\n });\n };\n\n dataChannelTimeoutId = setTimeout(_rejectTimeout, 5000);\n\n this._abortController.signal.addEventListener('abort', _rejectAbort);\n\n this.on('dataChannel', _resolve, this);\n });\n }\n }).then(r => {\n this.isPublished = true;\n\n if (config.stream) {\n let tracks = config.stream.getTracks();\n tracks.forEach(track => {\n // used as a flag to not emit tracks that been already emitted\n if (!track.onended) {\n var _decodeJanusDisplay21, _decodeJanusDisplay22;\n\n this.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: (_decodeJanusDisplay21 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay21 === void 0 ? void 0 : _decodeJanusDisplay21.userId,\n role: (_decodeJanusDisplay22 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(this.display)) === null || _decodeJanusDisplay22 === void 0 ? void 0 : _decodeJanusDisplay22.role,\n track,\n stream: config.stream,\n adding: true,\n constructId: this.constructId,\n metaData: this.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n\n track.onended = ev => {\n var _decodeJanusDisplay23, _decodeJanusDisplay24;\n\n this.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: (_decodeJanusDisplay23 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay23 === void 0 ? void 0 : _decodeJanusDisplay23.userId,\n role: (_decodeJanusDisplay24 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(this.display)) === null || _decodeJanusDisplay24 === void 0 ? void 0 : _decodeJanusDisplay24.role,\n track: ev.target,\n stream: config.stream,\n adding: false,\n removing: true,\n constructId: this.constructId,\n metaData: this.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n };\n }\n });\n } else {\n var _decodeJanusDisplay25, _decodeJanusDisplay26;\n\n this.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: (_decodeJanusDisplay25 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(handle.userId)) === null || _decodeJanusDisplay25 === void 0 ? void 0 : _decodeJanusDisplay25.userId,\n role: (_decodeJanusDisplay26 = Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"decodeJanusDisplay\"])(this.display)) === null || _decodeJanusDisplay26 === void 0 ? void 0 : _decodeJanusDisplay26.role,\n stream: null,\n adding: false,\n constructId: this.constructId,\n metaData: this.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n }\n\n this.emit('published', {\n status: true,\n hasStream: !!config.stream\n });\n this.emit('publishing', false);\n this.emit('localHasVideo', hasVideo);\n this.emit('localHasAudio', hasAudio);\n this.emit('localMuted', {\n type: 'video',\n value: isVideoMuted\n });\n this.emit('localMuted', {\n type: 'audio',\n value: isAudioMuted\n });\n return r;\n }).catch(e => {\n this.emit('publishing', false);\n return Promise.reject(e);\n });\n }\n\n unpublishLocal() {\n let dontWait = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n return this.isPublished ? this.sendMessage(this.handleId, {\n body: {\n \"request\": \"unpublish\"\n }\n }, dontWait).finally(r => {\n this.isPublished = false;\n this.emit('published', {\n status: false,\n hasStream: false\n });\n return r;\n }) : Promise.resolve();\n }\n\n toggleAudio() {\n let value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let mid = arguments.length > 1 ? arguments[1] : undefined;\n\n let handle = this._getHandle(this.handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'error',\n id: 21,\n message: 'no local id, connect first',\n data: null\n });\n }\n\n let config = handle.webrtcStuff;\n\n if (this.isUnifiedPlan) {\n let transceiver = config.pc.getTransceivers().find(t => t.sender && t.sender.track && t.receiver.track.kind === \"audio\" && t.stopped === false && (mid ? t.mid === mid : true));\n\n if (transceiver) {\n transceiver.sender.track.enabled = value !== null ? !!value : !transceiver.sender.track.enabled;\n }\n\n this.isAudioMuted = !transceiver || !transceiver.sender.track.enabled;\n } else {\n if (config.stream && config.stream.getAudioTracks().length) {\n config.stream.getAudioTracks()[0].enabled = value !== null ? !!value : !config.stream.getAudioTracks()[0].enabled;\n }\n\n this.isAudioMuted = config.stream.getAudioTracks().length === 0 || !config.stream.getAudioTracks()[0].enabled;\n }\n\n this.emit('localMuted', {\n type: 'audio',\n value: this.isAudioMuted,\n mid\n });\n }\n\n toggleVideo() {\n let value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let mid = arguments.length > 1 ? arguments[1] : undefined;\n\n let handle = this._getHandle(this.handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'error',\n id: 21,\n message: 'no local id, connect first',\n data: null\n });\n }\n\n let config = handle.webrtcStuff;\n\n if (this.isUnifiedPlan) {\n let transceiver = config.pc.getTransceivers().find(t => t.sender && t.sender.track && t.receiver.track.kind === \"video\" && t.stopped === false && (mid ? t.mid === mid : true));\n\n if (transceiver) {\n transceiver.sender.track.enabled = value !== null ? !!value : !transceiver.sender.track.enabled;\n }\n\n this.isVideoMuted = !transceiver || !transceiver.sender.track.enabled;\n } else {\n if (config.stream && config.stream.getVideoTracks().length) {\n config.stream.getVideoTracks()[0].enabled = value !== null ? !!value : !config.stream.getVideoTracks()[0].enabled;\n }\n\n this.isVideoMuted = config.stream.getVideoTracks().length === 0 || !config.stream.getVideoTracks()[0].enabled;\n }\n\n this.emit('localMuted', {\n type: 'video',\n value: this.isVideoMuted,\n mid\n });\n }\n\n setRoomType() {\n let type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'watchparty';\n this._roomType = type;\n return this._roomType;\n }\n\n}\n\n_defineProperty(RoomSession, \"sessionTypes\", {\n 'reactooroom': 'janus.plugin.reactooroom',\n 'streaming': 'janus.plugin.streaming'\n});\n\n_defineProperty(RoomSession, \"subscriptionRules\", {\n participant: {\n \"watchparty\": ['participant', 'talkback'],\n \"commentary\": ['participant', 'talkback', 'host'],\n \"videowall\": ['host', 'talkback', 'observer', 'observerSolo1', 'observerSolo2', 'observerSolo3'],\n \"videowall-queue\": ['host', 'talkback', 'observer', 'observerSolo1', 'observerSolo2', 'observerSolo3'],\n \"videowall-queue-video\": ['host', 'talkback', 'observer', 'observerSolo1', 'observerSolo2', 'observerSolo3']\n },\n monitor: {\n \"watchparty\": ['participant'],\n \"commentary\": ['participant', 'host'],\n \"videowall\": ['host', 'participant'],\n \"videowall-queue\": ['host', 'participant'],\n \"videowall-queue-video\": ['host', 'participant']\n },\n talkback: {\n \"watchparty\": ['participant'],\n \"commentary\": ['host', 'participant'],\n \"videowall\": ['host', 'participant'],\n \"videowall-queue\": ['host', 'participant'],\n \"videowall-queue-video\": ['host', 'participant']\n },\n observer: {\n \"watchparty\": ['participant'],\n \"commentary\": ['participant'],\n \"videowall\": ['participant'],\n \"videowall-queue\": ['participant'],\n \"videowall-queue-video\": ['participant']\n },\n observerSolo1: {\n \"watchparty\": ['participant'],\n \"commentary\": ['participant'],\n \"videowall\": ['participant'],\n \"videowall-queue\": ['participant'],\n \"videowall-queue-video\": ['participant']\n },\n observerSolo2: {\n \"watchparty\": ['participant'],\n \"commentary\": ['participant'],\n \"videowall\": ['participant'],\n \"videowall-queue\": ['participant'],\n \"videowall-queue-video\": ['participant']\n },\n observerSolo3: {\n \"watchparty\": ['participant'],\n \"commentary\": ['participant'],\n \"videowall\": ['participant'],\n \"videowall-queue\": ['participant'],\n \"videowall-queue-video\": ['participant']\n },\n host: {\n \"watchparty\": [],\n \"commentary\": [],\n \"videowall\": [],\n \"videowall-queue\": [],\n \"videowall-queue-video\": []\n },\n companionTV: {},\n companionPhone: {}\n});\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Room);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-room.js?");
9431
9431
 
9432
9432
  /***/ }),
9433
9433