@reactoo/watchtogether-sdk-js 2.5.25 → 2.5.30

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.25
3
+ * @version 2.5.30
4
4
  */
5
5
  (function webpackUniversalModuleDefinition(root, factory) {
6
6
  if(typeof exports === 'object' && typeof module === 'object')
@@ -9117,7 +9117,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n\n\nfunction _toConsumableArr
9117
9117
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9118
9118
 
9119
9119
  "use strict";
9120
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/wt-utils */ \"./src/modules/wt-utils.js\");\n/* harmony import */ var _modules_wt_emitter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../modules/wt-emitter */ \"./src/modules/wt-emitter.js\");\n/* harmony import */ var _modules_sync_modules_sync_hls__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../modules/sync-modules/sync-hls */ \"./src/modules/sync-modules/sync-hls.js\");\n/* harmony import */ var _modules_sync_modules_sync_hls_vod__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../modules/sync-modules/sync-hls-vod */ \"./src/modules/sync-modules/sync-hls-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_native_hls_vod__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../modules/sync-modules/sync-native-hls-vod */ \"./src/modules/sync-modules/sync-native-hls-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_native_hls__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../modules/sync-modules/sync-native-hls */ \"./src/modules/sync-modules/sync-native-hls.js\");\n/* harmony import */ var _modules_sync_modules_sync_shaka_dash__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../modules/sync-modules/sync-shaka-dash */ \"./src/modules/sync-modules/sync-shaka-dash.js\");\n/* harmony import */ var _modules_sync_modules_sync_shaka_dash_vod__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../modules/sync-modules/sync-shaka-dash-vod */ \"./src/modules/sync-modules/sync-shaka-dash-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_dash__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../modules/sync-modules/sync-dash */ \"./src/modules/sync-modules/sync-dash.js\");\n/* harmony import */ var _modules_sync_modules_sync_dash_vod__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../modules/sync-modules/sync-dash-vod */ \"./src/modules/sync-modules/sync-dash-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_doris__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../modules/sync-modules/sync-doris */ \"./src/modules/sync-modules/sync-doris.js\");\n/* harmony import */ var _modules_sync_modules_sync_disabled__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../modules/sync-modules/sync-disabled */ \"./src/modules/sync-modules/sync-disabled.js\");\n/* harmony import */ var _modules_sync_modules_sync_dazn_dash__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../modules/sync-modules/sync-dazn-dash */ \"./src/modules/sync-modules/sync-dazn-dash.js\");\n/* harmony import */ var _modules_sync_modules_sync_universal__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../modules/sync-modules/sync-universal */ \"./src/modules/sync-modules/sync-universal.js\");\n\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\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\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _iterableToArray(iter) { if (typeof Symbol !== \"undefined\" && iter[Symbol.iterator] != null || iter[\"@@iterator\"] != null) return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\n\n // SYNCHRONISATION MODULES\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nvar roomSession = function roomSession(_ref, room, wt) {\n var _this4 = this;\n\n var roomId = _ref.roomId,\n pinHash = _ref.pinHash,\n isTalkback = _ref.isTalkback,\n isMonitor = _ref.isMonitor,\n isInstructor = _ref.isInstructor;\n var primaryRoomId = roomId;\n var publicCustomEvents = ['changePlayerSource', 'chatMessage', 'userUpdate', 'reconnecting', 'connecting', 'remoteMuted', 'scaling'];\n\n var addEvents = function addEvents(events) {\n publicCustomEvents = [].concat(_toConsumableArray(publicCustomEvents), _toConsumableArray(events));\n };\n\n var removeEvents = function removeEvents(events) {\n publicCustomEvents = publicCustomEvents.filter(function (ev) {\n return events.indexOf(ev) === -1;\n });\n };\n\n var emitter = Object(_modules_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])();\n\n var alpTimeoutId = null;\n\n var ___; // return object\n\n\n room.on('addLocalParticipant', function () {\n // TODO: this doesnt seem to be fixable until we switch to different type of messaging\n // At some random case we don't get message back if we don't wait\n clearTimeout(alpTimeoutId);\n alpTimeoutId = setTimeout(function () {\n ___.__requestMuteStatus();\n }, 2000);\n });\n room.on('localMuted', function (_ref2) {\n var type = _ref2.type,\n value = _ref2.value;\n\n ___.sendSystemMessage('remote_muted', {\n type: type,\n value: value\n });\n });\n room.on('data', function (data) {\n ___.__parseDataEvents(data);\n });\n return ___ = {\n syncModule: null,\n playerInterface: null,\n\n get userId() {\n return room.userId;\n },\n\n get roomId() {\n return roomId;\n },\n\n get sessionId() {\n return room.sessionId;\n },\n\n get constructId() {\n return room.constructId;\n },\n\n destroy: function destroy() {\n var _this = this;\n\n clearTimeout(alpTimeoutId);\n this.detachPlayer();\n return room.destroy().finally(function () {\n _this.$clear();\n\n return true;\n });\n },\n iceRestart: function iceRestart() {\n return room._iceRestart(room.handleId);\n },\n connect: function connect() {\n var _this2 = this;\n\n var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref3$reactooRoomId = _ref3.reactooRoomId,\n reactooRoomId = _ref3$reactooRoomId === void 0 ? null : _ref3$reactooRoomId;\n\n emitter.emit('connecting', true);\n clearTimeout(alpTimeoutId);\n return Promise.all([wt.room.__joinRoom({\n roomId: reactooRoomId || primaryRoomId,\n pinHash: pinHash,\n isTalkback: isTalkback,\n isMonitor: isMonitor,\n isInstructor: isInstructor\n }), wt.user.getUserSelf()]).then(function (_ref4) {\n var _roomData$data;\n\n var _ref5 = _slicedToArray(_ref4, 2),\n roomData = _ref5[0],\n userData = _ref5[1];\n\n // Happens when we reroute user to a different room\n if ((roomData === null || roomData === void 0 ? void 0 : (_roomData$data = roomData.data) === null || _roomData$data === void 0 ? void 0 : _roomData$data.reactooRoomId) !== roomId) {\n roomId = roomData.data.reactooRoomId;\n emitter.emit('changeRoomId', roomId);\n }\n\n return Promise.all([roomData, userData]);\n }).then(function (_ref6) {\n var _ref7 = _slicedToArray(_ref6, 2),\n roomData = _ref7[0],\n userData = _ref7[1];\n\n return Promise.all([roomData, userData, _this2.setRoomVars()]);\n }).then(function (_ref8) {\n var _ref9 = _slicedToArray(_ref8, 3),\n roomData = _ref9[0],\n userData = _ref9[1],\n _ = _ref9[2];\n\n return Promise.all([roomData, userData, room.connect(roomData.data.roomId, roomData.data.pin, roomData.data.href, roomData.data.iceServers, roomData.data.accessToken, isMonitor || isInstructor || isTalkback ? roomData.data.userId : userData.data._id, roomData.data.webrtcVersion, roomData.data.bitrate ? parseInt(roomData.data.bitrate) : 0, isMonitor, roomData.data.recordingFilename)]);\n }).finally(function () {\n emitter.emit('connecting', false);\n });\n },\n disconnect: function disconnect(dontWaitForResponses) {\n clearTimeout(alpTimeoutId);\n return room.disconnect(dontWaitForResponses);\n },\n //TODO: refactor restart method\n restart: function restart() {\n var _handle$webrtcStuff,\n _this3 = this;\n\n var _ref10 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref10$isObserver = _ref10.isObserver,\n isObserver = _ref10$isObserver === void 0 ? false : _ref10$isObserver,\n _ref10$reactooRoomId = _ref10.reactooRoomId,\n reactooRoomId = _ref10$reactooRoomId === void 0 ? null : _ref10$reactooRoomId;\n\n emitter.emit('reconnecting', true);\n room.isRestarting = true;\n var wasPublished = room._isPublished;\n\n var handle = room._getHandle(room.handleId);\n\n var stream = null;\n\n if (handle !== null && handle !== void 0 && (_handle$webrtcStuff = handle.webrtcStuff) !== null && _handle$webrtcStuff !== void 0 && _handle$webrtcStuff.stream && wasPublished) {\n stream = handle.webrtcStuff.stream;\n }\n\n return this.disconnect().then(function () {\n return Object(_modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(1000);\n }) //TODO: remove 1000ms wait by waiting for proper events from janus\n .then(function () {\n return _this3.connect({\n reactooRoomId: reactooRoomId\n });\n }).then(function () {\n if (isObserver) {\n return _this3.publishLocal(null);\n } else if (stream) {\n return _this3.publishLocal(stream);\n } else return Promise.resolve();\n }).then(function () {\n room.isRestarting = false;\n emitter.emit('reconnecting', false);\n return 1;\n }).catch(function (error) {\n room.isRestarting = false;\n emitter.emit('reconnecting', false);\n emitter.emit('error', {\n type: 'error',\n id: 26,\n message: 'reconnecting failed',\n data: error\n });\n return Promise.reject(0);\n });\n },\n getStats: function getStats() {\n var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n return room._getStats(type);\n },\n getRoomParticipants: function getRoomParticipants() {\n return room._participants;\n },\n __parseDataEvents: function __parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'message') {\n if (msg.action === 'pending_shutdown' || msg.action === 'shutting_down') {\n emitter.emit('scaling');\n this.restart(); // current videoroom was reassigned to a different WebRTC instance\n } else if (msg.action === 'force_restart') {\n this.restart();\n } else if (msg.action === 'user_update_displayname' || msg.action === 'user_update_avatar' || msg.action === 'user_update_customattributes' || msg.action === 'user_update_privateattributes') {\n emitter.emit('userUpdate', msg.text);\n } else if (msg.action === 'observer_connecting' || msg.action === 'talkback_connecting' || msg.action === 'instructor_connecting') {\n this.setRoomVars(null, msg.action === 'observer_connecting').catch(function (e) {\n room._log('Setting observers failed, this will cause issues', e);\n });\n } else if (msg.action === 'bitrate_changed') {\n this.setBitrateCap(msg.text);\n } else if (msg.user_action === 'chat_message') {\n emitter.emit('chatMessage', msg);\n } else if (msg.user_action === 'remote_muted') {\n if (msg.from !== room.userId) {\n emitter.emit('remoteMuted', _objectSpread({\n userId: msg.from\n }, msg.text && JSON.parse(msg.text)));\n }\n } else if (msg.user_action === 'remote_muted_request') {\n if (msg.from !== room.userId) {\n this.__sendMuteStatus();\n }\n }\n }\n },\n renderPlayer: function renderPlayer(playerWrapper, fullscreenElement, roomId) {\n try {\n this.syncModule = Object(_modules_sync_modules_sync_universal__WEBPACK_IMPORTED_MODULE_13__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n this.playerInterface = wt.__privates.playerFactory(playerWrapper, fullscreenElement, this.syncModule.getHandlers(), {\n roomId: roomId\n });\n this.syncModule.initialize({\n playerInterface: this.playerInterface\n });\n return true;\n } catch (e) {\n return false;\n }\n },\n attachPlayer: function attachPlayer(type, inputs) {\n this.detachPlayer();\n\n if (type === 'hlsjs') {\n this.syncModule = Object(_modules_sync_modules_sync_hls__WEBPACK_IMPORTED_MODULE_2__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'hlsjs-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_hls_vod__WEBPACK_IMPORTED_MODULE_3__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'hlsnative-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_native_hls_vod__WEBPACK_IMPORTED_MODULE_4__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'hlsnative') {\n this.syncModule = Object(_modules_sync_modules_sync_native_hls__WEBPACK_IMPORTED_MODULE_5__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'shaka-dash-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_shaka_dash_vod__WEBPACK_IMPORTED_MODULE_7__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'shaka-dash') {\n this.syncModule = Object(_modules_sync_modules_sync_shaka_dash__WEBPACK_IMPORTED_MODULE_6__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'dashjs') {\n this.syncModule = Object(_modules_sync_modules_sync_dash__WEBPACK_IMPORTED_MODULE_8__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'dashjs-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_dash_vod__WEBPACK_IMPORTED_MODULE_9__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'doris') {\n this.syncModule = Object(_modules_sync_modules_sync_doris__WEBPACK_IMPORTED_MODULE_10__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'dazn-dash') {\n this.syncModule = Object(_modules_sync_modules_sync_dazn_dash__WEBPACK_IMPORTED_MODULE_12__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'disabled') {\n this.syncModule = Object(_modules_sync_modules_sync_disabled__WEBPACK_IMPORTED_MODULE_11__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else {\n room._log('Synchronisation type not recognised');\n }\n },\n detachPlayer: function detachPlayer() {\n if (this.syncModule) {\n this.playerInterface = null;\n this.syncModule.destroy();\n\n if (this.syncModule.__events) {\n removeEvents(this.syncModule.__events);\n }\n\n this.syncModule = null;\n }\n },\n setRoomVars: function setRoomVars() {\n var observerIds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n var emit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n return wt.room.getRoomById(roomId, pinHash).then(function (r) {\n var _r$data$classroom;\n\n if (emit) {\n // emiting \"fake\" playerSource event\n //TODO: somehow push into sync modules instead\n emitter.emit('changePlayerSource', r.data.wtChannelId, true);\n } // setting observers userId's so we can ignore them when creating participant\n\n\n room.setObserverIds(r.data.allowedObservers);\n room.setTalkbackIds(r.data.allowedTalkbacks);\n room.setInstructorId((_r$data$classroom = r.data.classroom) === null || _r$data$classroom === void 0 ? void 0 : _r$data$classroom.instructorUserId);\n });\n },\n publishLocal: function publishLocal() {\n var stream = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n\n var _ref11 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n _ref11$keepAudio = _ref11.keepAudio,\n keepAudio = _ref11$keepAudio === void 0 ? false : _ref11$keepAudio,\n _ref11$keepVideo = _ref11.keepVideo,\n keepVideo = _ref11$keepVideo === void 0 ? false : _ref11$keepVideo;\n\n return room.publishLocal(stream, {\n keepAudio: keepAudio,\n keepVideo: keepVideo\n });\n },\n unpublishLocal: function unpublishLocal() {\n return room.unpublishLocal();\n },\n toggleAudio: function toggleAudio(value) {\n return room.toggleAudio(value);\n },\n toggleVideo: function toggleVideo() {\n return room.toggleVideo();\n },\n setBitrateCap: function setBitrateCap(bitrate) {\n if (isInstructor) {\n return;\n }\n\n return room.sendMessage(room.handleId, {\n \"body\": {\n \"request\": \"configure\",\n \"bitrate\": parseInt(bitrate)\n }\n }).catch(function () {\n return null;\n });\n },\n switchChannel: function switchChannel(channelId) {\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: channelId,\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n },\n sendSystemMessage: function sendSystemMessage(action) {\n var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n var to = arguments.length > 2 ? arguments[2] : undefined;\n var set_master = arguments.length > 3 ? arguments[3] : undefined;\n return room.sendMessage(room.handleId, {\n body: _objectSpread(_objectSpread({\n action: action,\n request: \"message\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n text: JSON.stringify(value)\n }, to && Array.isArray(to) ? {\n tos: to\n } : {\n to: to\n }), set_master && {\n set_master: set_master\n })\n });\n },\n sendChatMessage: function sendChatMessage(text, to) {\n return room.sendMessage(room.handleId, {\n body: _objectSpread({\n action: \"chat_message\",\n request: \"message\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n text: text\n }, to && Array.isArray(to) ? {\n tos: to\n } : {\n to: to\n })\n });\n },\n __requestMuteStatus: function __requestMuteStatus() {\n this.sendSystemMessage('remote_muted_request');\n },\n __sendMuteStatus: function __sendMuteStatus() {\n this.sendSystemMessage('remote_muted', {\n type: 'video',\n value: room.isVideoMuted\n });\n this.sendSystemMessage('remote_muted', {\n type: 'audio',\n value: room.isAudioMuted\n });\n },\n $on: function $on(key, callback, that) {\n emitter.on(key, callback, that || _this4);\n room.on(key, callback, that || _this4);\n },\n $off: function $off(key, callback, that) {\n emitter.on(key, callback, that || _this4);\n room.on(key, callback, that || _this4);\n },\n $clear: function $clear() {\n room.clear();\n emitter.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (roomSession);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/room-session.js?");
9120
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/wt-utils */ \"./src/modules/wt-utils.js\");\n/* harmony import */ var _modules_wt_emitter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../modules/wt-emitter */ \"./src/modules/wt-emitter.js\");\n/* harmony import */ var _modules_sync_modules_sync_hls__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../modules/sync-modules/sync-hls */ \"./src/modules/sync-modules/sync-hls.js\");\n/* harmony import */ var _modules_sync_modules_sync_hls_vod__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../modules/sync-modules/sync-hls-vod */ \"./src/modules/sync-modules/sync-hls-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_native_hls_vod__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../modules/sync-modules/sync-native-hls-vod */ \"./src/modules/sync-modules/sync-native-hls-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_native_hls__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../modules/sync-modules/sync-native-hls */ \"./src/modules/sync-modules/sync-native-hls.js\");\n/* harmony import */ var _modules_sync_modules_sync_shaka_dash__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../modules/sync-modules/sync-shaka-dash */ \"./src/modules/sync-modules/sync-shaka-dash.js\");\n/* harmony import */ var _modules_sync_modules_sync_shaka_dash_vod__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../modules/sync-modules/sync-shaka-dash-vod */ \"./src/modules/sync-modules/sync-shaka-dash-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_dash__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../modules/sync-modules/sync-dash */ \"./src/modules/sync-modules/sync-dash.js\");\n/* harmony import */ var _modules_sync_modules_sync_dash_vod__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../modules/sync-modules/sync-dash-vod */ \"./src/modules/sync-modules/sync-dash-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_doris__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../modules/sync-modules/sync-doris */ \"./src/modules/sync-modules/sync-doris.js\");\n/* harmony import */ var _modules_sync_modules_sync_disabled__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../modules/sync-modules/sync-disabled */ \"./src/modules/sync-modules/sync-disabled.js\");\n/* harmony import */ var _modules_sync_modules_sync_dazn_dash__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../modules/sync-modules/sync-dazn-dash */ \"./src/modules/sync-modules/sync-dazn-dash.js\");\n/* harmony import */ var _modules_sync_modules_sync_universal__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../modules/sync-modules/sync-universal */ \"./src/modules/sync-modules/sync-universal.js\");\n\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\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\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _iterableToArray(iter) { if (typeof Symbol !== \"undefined\" && iter[Symbol.iterator] != null || iter[\"@@iterator\"] != null) return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\n\n // SYNCHRONISATION MODULES\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nvar roomSession = function roomSession(_ref, room, wt) {\n var _this4 = this;\n\n var roomId = _ref.roomId,\n pinHash = _ref.pinHash,\n isTalkback = _ref.isTalkback,\n isMonitor = _ref.isMonitor,\n isInstructor = _ref.isInstructor;\n var primaryRoomId = roomId;\n var publicCustomEvents = ['changePlayerSource', 'chatMessage', 'userUpdate', 'reconnecting', 'connecting', 'remoteMuted', 'scaling'];\n\n var addEvents = function addEvents(events) {\n publicCustomEvents = [].concat(_toConsumableArray(publicCustomEvents), _toConsumableArray(events));\n };\n\n var removeEvents = function removeEvents(events) {\n publicCustomEvents = publicCustomEvents.filter(function (ev) {\n return events.indexOf(ev) === -1;\n });\n };\n\n var emitter = Object(_modules_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])();\n\n var alpTimeoutId = null;\n\n var ___; // return object\n\n\n room.on('addLocalParticipant', function () {\n // TODO: this doesnt seem to be fixable until we switch to different type of messaging\n // At some random case we don't get message back if we don't wait\n clearTimeout(alpTimeoutId);\n alpTimeoutId = setTimeout(function () {\n ___.__requestMuteStatus();\n }, 2000);\n });\n room.on('localMuted', function (_ref2) {\n var type = _ref2.type,\n value = _ref2.value;\n\n ___.sendSystemMessage('remote_muted', {\n type: type,\n value: value\n });\n });\n room.on('data', function (data) {\n ___.__parseDataEvents(data);\n });\n return ___ = {\n syncModule: null,\n playerInterface: null,\n\n get userId() {\n return room.userId;\n },\n\n get roomId() {\n return roomId;\n },\n\n get sessionId() {\n return room.sessionId;\n },\n\n get constructId() {\n return room.constructId;\n },\n\n destroy: function destroy() {\n var _this = this;\n\n clearTimeout(alpTimeoutId);\n this.detachPlayer();\n return room.destroy().finally(function () {\n _this.$clear();\n\n return true;\n });\n },\n iceRestart: function iceRestart() {\n return room._iceRestart(room.handleId);\n },\n connect: function connect() {\n var _this2 = this;\n\n var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref3$reactooRoomId = _ref3.reactooRoomId,\n reactooRoomId = _ref3$reactooRoomId === void 0 ? null : _ref3$reactooRoomId;\n\n emitter.emit('connecting', true);\n clearTimeout(alpTimeoutId);\n return Promise.all([wt.room.__joinRoom({\n roomId: reactooRoomId || primaryRoomId,\n pinHash: pinHash,\n isTalkback: isTalkback,\n isMonitor: isMonitor,\n isInstructor: isInstructor\n }), wt.user.getUserSelf()]).then(function (_ref4) {\n var _roomData$data;\n\n var _ref5 = _slicedToArray(_ref4, 2),\n roomData = _ref5[0],\n userData = _ref5[1];\n\n // Happens when we reroute user to a different room\n if ((roomData === null || roomData === void 0 ? void 0 : (_roomData$data = roomData.data) === null || _roomData$data === void 0 ? void 0 : _roomData$data.reactooRoomId) !== roomId) {\n roomId = roomData.data.reactooRoomId;\n emitter.emit('changeRoomId', roomId);\n }\n\n return Promise.all([roomData, userData]);\n }).then(function (_ref6) {\n var _ref7 = _slicedToArray(_ref6, 2),\n roomData = _ref7[0],\n userData = _ref7[1];\n\n return Promise.all([roomData, userData, _this2.setRoomVars()]);\n }).then(function (_ref8) {\n var _ref9 = _slicedToArray(_ref8, 3),\n roomData = _ref9[0],\n userData = _ref9[1],\n _ = _ref9[2];\n\n return Promise.all([roomData, userData, room.connect(roomData.data.roomId, roomData.data.pin, roomData.data.href, roomData.data.iceServers, roomData.data.accessToken, roomData.data.display, roomData.data.userId, roomData.data.webrtcVersion, roomData.data.bitrate ? parseInt(roomData.data.bitrate) : 0, isMonitor, roomData.data.recordingFilename)]);\n }).finally(function () {\n emitter.emit('connecting', false);\n });\n },\n disconnect: function disconnect(dontWaitForResponses) {\n clearTimeout(alpTimeoutId);\n return room.disconnect(dontWaitForResponses);\n },\n //TODO: refactor restart method\n restart: function restart() {\n var _handle$webrtcStuff,\n _this3 = this;\n\n var _ref10 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref10$isObserver = _ref10.isObserver,\n isObserver = _ref10$isObserver === void 0 ? false : _ref10$isObserver,\n _ref10$reactooRoomId = _ref10.reactooRoomId,\n reactooRoomId = _ref10$reactooRoomId === void 0 ? null : _ref10$reactooRoomId;\n\n emitter.emit('reconnecting', true);\n room.isRestarting = true;\n var wasPublished = room._isPublished;\n\n var handle = room._getHandle(room.handleId);\n\n var stream = null;\n\n if (handle !== null && handle !== void 0 && (_handle$webrtcStuff = handle.webrtcStuff) !== null && _handle$webrtcStuff !== void 0 && _handle$webrtcStuff.stream && wasPublished) {\n stream = handle.webrtcStuff.stream;\n }\n\n return this.disconnect().then(function () {\n return Object(_modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(1000);\n }) //TODO: remove 1000ms wait by waiting for proper events from janus\n .then(function () {\n return _this3.connect({\n reactooRoomId: reactooRoomId\n });\n }).then(function () {\n if (isObserver) {\n return _this3.publishLocal(null);\n } else if (stream) {\n return _this3.publishLocal(stream);\n } else return Promise.resolve();\n }).then(function () {\n room.isRestarting = false;\n emitter.emit('reconnecting', false);\n return 1;\n }).catch(function (error) {\n room.isRestarting = false;\n emitter.emit('reconnecting', false);\n emitter.emit('error', {\n type: 'error',\n id: 26,\n message: 'reconnecting failed',\n data: error\n });\n return Promise.reject(0);\n });\n },\n getStats: function getStats() {\n var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n return room._getStats(type);\n },\n getRoomParticipants: function getRoomParticipants() {\n return room._participants;\n },\n __parseDataEvents: function __parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'message') {\n if (msg.action === 'pending_shutdown' || msg.action === 'shutting_down') {\n emitter.emit('scaling');\n this.restart(); // current videoroom was reassigned to a different WebRTC instance\n } else if (msg.action === 'force_restart') {\n this.restart();\n } else if (msg.action === 'user_update_displayname' || msg.action === 'user_update_avatar' || msg.action === 'user_update_customattributes' || msg.action === 'user_update_privateattributes') {\n emitter.emit('userUpdate', msg.text);\n } else if (msg.action === 'observer_connecting' || msg.action === 'talkback_connecting' || msg.action === 'instructor_connecting') {\n this.setRoomVars().catch(function (e) {\n room._log('Setting observers failed, this will cause issues', e);\n });\n } else if (msg.action === 'bitrate_changed') {\n this.setBitrateCap(msg.text);\n } else if (msg.user_action === 'chat_message') {\n emitter.emit('chatMessage', msg);\n } else if (msg.user_action === 'remote_muted') {\n if (msg.from !== room.userId) {\n emitter.emit('remoteMuted', _objectSpread({\n userId: msg.from\n }, msg.text && JSON.parse(msg.text)));\n }\n } else if (msg.user_action === 'remote_muted_request') {\n if (msg.from !== room.userId) {\n this.__sendMuteStatus();\n }\n }\n }\n },\n renderPlayer: function renderPlayer(playerWrapper, fullscreenElement, roomId) {\n try {\n this.syncModule = Object(_modules_sync_modules_sync_universal__WEBPACK_IMPORTED_MODULE_13__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n this.playerInterface = wt.__privates.playerFactory(playerWrapper, fullscreenElement, this.syncModule.getHandlers(), {\n roomId: roomId\n });\n this.syncModule.initialize({\n playerInterface: this.playerInterface\n });\n return true;\n } catch (e) {\n return false;\n }\n },\n attachPlayer: function attachPlayer(type, inputs) {\n this.detachPlayer();\n\n if (type === 'hlsjs') {\n this.syncModule = Object(_modules_sync_modules_sync_hls__WEBPACK_IMPORTED_MODULE_2__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'hlsjs-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_hls_vod__WEBPACK_IMPORTED_MODULE_3__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'hlsnative-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_native_hls_vod__WEBPACK_IMPORTED_MODULE_4__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'hlsnative') {\n this.syncModule = Object(_modules_sync_modules_sync_native_hls__WEBPACK_IMPORTED_MODULE_5__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'shaka-dash-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_shaka_dash_vod__WEBPACK_IMPORTED_MODULE_7__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'shaka-dash') {\n this.syncModule = Object(_modules_sync_modules_sync_shaka_dash__WEBPACK_IMPORTED_MODULE_6__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'dashjs') {\n this.syncModule = Object(_modules_sync_modules_sync_dash__WEBPACK_IMPORTED_MODULE_8__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'dashjs-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_dash_vod__WEBPACK_IMPORTED_MODULE_9__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'doris') {\n this.syncModule = Object(_modules_sync_modules_sync_doris__WEBPACK_IMPORTED_MODULE_10__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'dazn-dash') {\n this.syncModule = Object(_modules_sync_modules_sync_dazn_dash__WEBPACK_IMPORTED_MODULE_12__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'disabled') {\n this.syncModule = Object(_modules_sync_modules_sync_disabled__WEBPACK_IMPORTED_MODULE_11__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else {\n room._log('Synchronisation type not recognised');\n }\n },\n detachPlayer: function detachPlayer() {\n if (this.syncModule) {\n this.playerInterface = null;\n this.syncModule.destroy();\n\n if (this.syncModule.__events) {\n removeEvents(this.syncModule.__events);\n }\n\n this.syncModule = null;\n }\n },\n setRoomVars: function setRoomVars() {\n return wt.room.getRoomById(roomId, pinHash).then(function (r) {\n var _r$data$classroom;\n\n // setting observers userId's so we can ignore them when creating participant\n room.setObserverIds(r.data.allowedObservers);\n room.setTalkbackIds(r.data.allowedTalkbacks);\n room.setInstructorId((_r$data$classroom = r.data.classroom) === null || _r$data$classroom === void 0 ? void 0 : _r$data$classroom.instructorUserId);\n });\n },\n publishLocal: function publishLocal() {\n var stream = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n\n var _ref11 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n _ref11$keepAudio = _ref11.keepAudio,\n keepAudio = _ref11$keepAudio === void 0 ? false : _ref11$keepAudio,\n _ref11$keepVideo = _ref11.keepVideo,\n keepVideo = _ref11$keepVideo === void 0 ? false : _ref11$keepVideo;\n\n return room.publishLocal(stream, {\n keepAudio: keepAudio,\n keepVideo: keepVideo\n });\n },\n unpublishLocal: function unpublishLocal() {\n return room.unpublishLocal();\n },\n toggleAudio: function toggleAudio(value) {\n return room.toggleAudio(value);\n },\n toggleVideo: function toggleVideo() {\n return room.toggleVideo();\n },\n setBitrateCap: function setBitrateCap(bitrate) {\n if (isInstructor) {\n return;\n }\n\n return room.sendMessage(room.handleId, {\n \"body\": {\n \"request\": \"configure\",\n \"bitrate\": parseInt(bitrate)\n }\n }).catch(function () {\n return null;\n });\n },\n switchChannel: function switchChannel(channelId) {\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: channelId,\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n },\n sendSystemMessage: function sendSystemMessage(action) {\n var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n var to = arguments.length > 2 ? arguments[2] : undefined;\n var set_master = arguments.length > 3 ? arguments[3] : undefined;\n return room.sendMessage(room.handleId, {\n body: _objectSpread(_objectSpread({\n action: action,\n request: \"message\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n text: JSON.stringify(value)\n }, to && Array.isArray(to) ? {\n tos: to\n } : {\n to: to\n }), set_master && {\n set_master: set_master\n })\n });\n },\n sendChatMessage: function sendChatMessage(text, to) {\n return room.sendMessage(room.handleId, {\n body: _objectSpread({\n action: \"chat_message\",\n request: \"message\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n text: text\n }, to && Array.isArray(to) ? {\n tos: to\n } : {\n to: to\n })\n });\n },\n __requestMuteStatus: function __requestMuteStatus() {\n this.sendSystemMessage('remote_muted_request');\n },\n __sendMuteStatus: function __sendMuteStatus() {\n this.sendSystemMessage('remote_muted', {\n type: 'video',\n value: room.isVideoMuted\n });\n this.sendSystemMessage('remote_muted', {\n type: 'audio',\n value: room.isAudioMuted\n });\n },\n $on: function $on(key, callback, that) {\n emitter.on(key, callback, that || _this4);\n room.on(key, callback, that || _this4);\n },\n $off: function $off(key, callback, that) {\n emitter.on(key, callback, that || _this4);\n room.on(key, callback, that || _this4);\n },\n $clear: function $clear() {\n room.clear();\n emitter.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (roomSession);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/room-session.js?");
9121
9121
 
9122
9122
  /***/ }),
9123
9123
 
@@ -9189,7 +9189,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n\n\nfunction ownKeys(object,
9189
9189
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9190
9190
 
9191
9191
  "use strict";
9192
- 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\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\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\n\nvar syncVodDashJs = function syncVodDashJs() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var _roomId = null;\n var _syncDisabled = false;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var seekingDebounceId = null;\n var seekingDebounceTimeout = 300;\n var isPlaying = false;\n var isProgrammaticallySeeked = false;\n var isForcedMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (_syncDisabled) {\n room._log('--- Sync loop will not start due to sync force disabled ---');\n\n return;\n }\n\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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (syncData.masterFragmentSn) {\n playMedia();\n } else {\n pauseMedia();\n }\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(position + (isPlaying ? seekDuration : 0) - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement) {\n //TODO: shit fix ... data channel with other participant is not opened yet so we wait\n setTimeout(function () {\n restartSyncLoop();\n }, 1000);\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var handleRemoveRemoteParticipant = function handleRemoveRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var buffering = function buffering(event) {\n if (event.mediaType === 'video' || event.mediaType === 'audio') {\n if (event.state === 'bufferStalled') {\n handleStalledWaiting();\n }\n }\n };\n\n var executePlayerIotEvents = function executePlayerIotEvents(data) {\n var rid = _roomId || room.roomId;\n\n if (data.attributeName === 'playerReplay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n seekTo(0).then(function () {\n return playMedia();\n });\n }\n\n if (data.attributeName === 'playerPlay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n playMedia();\n }\n\n if (data.attributeName === 'playerPause' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n pauseMedia();\n }\n };\n\n var parseIotEvents = function parseIotEvents(data) {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(function (event) {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents(_objectSpread(_objectSpread({}, event), {}, {\n roomId: data.roomId,\n userId: data.userId\n }));\n }\n });\n }\n\n if (data.operation === 'sendMessage') {\n executePlayerIotEvents(data);\n }\n }\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n } else if (msg.videoroom === 'message') {\n // ignoring non studio commands if master\n if (isForcedMaster && msg.from !== null) {\n return;\n }\n\n if (_syncDisabled) {\n return;\n }\n\n if (msg.user_action === 'sync_seeking') {\n seekMedia(msg).catch(function () {});\n } else if (msg.user_action === 'sync_seeked') {} else if (msg.user_action === 'sync_play' || msg.action === 'sync_play') {\n playMedia();\n } else if (msg.user_action === 'sync_pause' || msg.action === 'sync_pause') {\n pauseMedia();\n }\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn) {\n var fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n var seekMedia = function seekMedia(msg) {\n msg = _objectSpread({\n userId: msg.from\n }, msg.text && JSON.parse(msg.text));\n\n if (msg.handleId !== room.handleId) {\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0),\n position = _calculateSyncDiffere2.position,\n isBufferSufficient = _calculateSyncDiffere2.isBufferSufficient; //TODO: right ping\n\n\n if (position) {\n return seekTo(position).then(function () {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n var prePlay = function prePlay() {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n var wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(function () {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(function () {\n return true;\n }).finally(function () {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n var playMedia = function playMedia() {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(function () {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n var pauseMedia = function pauseMedia() {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', function () {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve) {\n if (_videoElement.currentTime !== time) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('seeked', function () {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(function () {});\n }\n };\n\n var handleSeeking = function handleSeeking() {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(function () {\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n roomSession.sendSystemMessage('sync_seeking', {\n timestamp: new Date().getTime(),\n handleId: room.handleId,\n fragment: \"0\",\n //isPlaying ? \"1\":\"0\",\n fragment_pos: Number(fragmentPosition)\n }, undefined, null).catch(function () {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n var handleSeeked = function handleSeeked() {};\n\n var handleEnded = function handleEnded() {};\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n dashInstance = _ref2.dashInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster,\n _ref2$isStudio = _ref2.isStudio,\n isStudio = _ref2$isStudio === void 0 ? false : _ref2$isStudio,\n roomId = _ref2.roomId,\n syncDisabled = _ref2.syncDisabled;\n\n _libraryInstance = dashInstance || libraryInstance;\n _videoElement = _libraryInstance.getVideoElement();\n _roomId = roomId;\n _syncDisabled = syncDisabled;\n\n if (!_libraryInstance) {\n console.log('No player instance');\n return;\n }\n\n emitter.emit('playerSyncing', false);\n isForcedMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.on('data', parseDataEvents);\n wt.iot.$on('message', parseIotEvents);\n\n if (isForcedMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_libraryInstance && _videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(function () {\n _libraryInstance.on('bufferStateChanged', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n\n _videoElement.addEventListener('seeking', handleSeeking);\n\n _videoElement.addEventListener('seeked', handleSeeked);\n\n _videoElement.addEventListener('ended', handleEnded);\n\n startSyncLoop();\n });\n }\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_libraryInstance) {\n _libraryInstance.off('bufferStateChanged', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _libraryInstance = null;\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodDashJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-dash-vod.js?");
9192
+ 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\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\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\n\nvar syncVodDashJs = function syncVodDashJs() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var _roomId = null;\n var _syncDisabled = false;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var seekingDebounceId = null;\n var seekingDebounceTimeout = 300;\n var isPlaying = false;\n var isProgrammaticallySeeked = false;\n var isForcedMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (_syncDisabled) {\n room._log('--- Sync loop will not start due to sync force disabled ---');\n\n return;\n }\n\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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (syncData.masterFragmentSn) {\n playMedia();\n } else {\n pauseMedia();\n }\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(position + (isPlaying ? seekDuration : 0) - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement) {\n //TODO: shit fix ... data channel with other participant is not opened yet so we wait\n setTimeout(function () {\n restartSyncLoop();\n }, 1000);\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var handleRemoveRemoteParticipant = function handleRemoveRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var buffering = function buffering(event) {\n if (event.mediaType === 'video' || event.mediaType === 'audio') {\n if (event.state === 'bufferStalled') {\n handleStalledWaiting();\n }\n }\n };\n\n var executePlayerIotEvents = function executePlayerIotEvents(data) {\n var rid = _roomId || room.roomId;\n\n if (data.attributeName === 'playerReplay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n seekTo(0).then(function () {\n return playMedia();\n });\n }\n\n if (data.attributeName === 'playerPlay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n playMedia();\n }\n\n if (data.attributeName === 'playerPause' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n pauseMedia();\n }\n };\n\n var parseIotEvents = function parseIotEvents(data) {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(function (event) {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents(_objectSpread(_objectSpread({}, event), {}, {\n roomId: data.roomId,\n userId: data.userId\n }));\n }\n });\n }\n\n if (data.operation === 'sendMessage') {\n executePlayerIotEvents(data);\n }\n }\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n } else if (msg.videoroom === 'message') {\n // ignoring non studio commands if master\n if (isForcedMaster && msg.from !== null) {\n return;\n }\n\n if (_syncDisabled) {\n return;\n }\n\n if (msg.user_action === 'sync_seeking') {\n seekMedia(msg).catch(function () {});\n } else if (msg.user_action === 'sync_seeked') {} else if (msg.user_action === 'sync_play' || msg.action === 'sync_play') {\n playMedia();\n } else if (msg.user_action === 'sync_pause' || msg.action === 'sync_pause') {\n pauseMedia();\n }\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn) {\n var fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n var seekMedia = function seekMedia(msg) {\n msg = _objectSpread({\n userId: msg.from\n }, msg.text && JSON.parse(msg.text));\n\n if (msg.handleId !== room.handleId) {\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0),\n position = _calculateSyncDiffere2.position,\n isBufferSufficient = _calculateSyncDiffere2.isBufferSufficient; //TODO: right ping\n\n\n if (position) {\n return seekTo(position).then(function () {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n var prePlay = function prePlay() {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n var wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(function () {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(function () {\n return true;\n }).finally(function () {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n var playMedia = function playMedia() {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(function () {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n var pauseMedia = function pauseMedia() {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', function () {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve) {\n if (_videoElement.currentTime !== time) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('seeked', function () {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(function () {});\n }\n };\n\n var handleSeeking = function handleSeeking() {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(function () {\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n roomSession.sendSystemMessage('sync_seeking', {\n timestamp: new Date().getTime(),\n handleId: room.handleId,\n fragment: \"0\",\n //isPlaying ? \"1\":\"0\",\n fragment_pos: Number(fragmentPosition)\n }, undefined, null).catch(function () {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n var handleSeeked = function handleSeeked() {};\n\n var handleEnded = function handleEnded() {};\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n dashInstance = _ref2.dashInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster,\n _ref2$isStudio = _ref2.isStudio,\n isStudio = _ref2$isStudio === void 0 ? false : _ref2$isStudio,\n roomId = _ref2.roomId,\n syncDisabled = _ref2.syncDisabled;\n\n _libraryInstance = dashInstance || libraryInstance;\n _videoElement = _libraryInstance.getVideoElement();\n _roomId = roomId;\n _syncDisabled = syncDisabled;\n\n if (!_libraryInstance) {\n console.log('No player instance');\n return;\n }\n\n emitter.emit('playerSyncing', false);\n isForcedMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.on('data', parseDataEvents);\n wt.iot.$on('message', parseIotEvents);\n\n if (isForcedMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_libraryInstance && _videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(function () {\n _libraryInstance.on('bufferStateChanged', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n\n _videoElement.addEventListener('seeking', handleSeeking);\n\n _videoElement.addEventListener('seeked', handleSeeked);\n\n _videoElement.addEventListener('ended', handleEnded);\n\n startSyncLoop();\n });\n }\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_libraryInstance) {\n _libraryInstance.off('bufferStateChanged', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _libraryInstance = null;\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodDashJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-dash-vod.js?");
9193
9193
 
9194
9194
  /***/ }),
9195
9195
 
@@ -9201,7 +9201,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9201
9201
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9202
9202
 
9203
9203
  "use strict";
9204
- 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\n\nvar syncDashJs = function syncDashJs() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var startSyncLoop = function 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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n realPosition = _calculateSyncDiffere.realPosition,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var buffering = function buffering(event) {\n if (event.mediaType === 'video' || event.mediaType === 'audio') {\n if (event.state === 'bufferStalled') {\n handleStalledWaiting();\n }\n }\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos, ping) {\n var seekRanges = _videoElement.buffered;\n var seekRange = {};\n\n for (var i = 0; i < seekRanges.length; i++) {\n var _c_start = seekRanges.start(i);\n\n var _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 var position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position: position,\n realPosition: position,\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,\n realPosition: position,\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,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPosition: position,\n isBufferSufficient: false\n };\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve, reject) {\n if (_videoElement.currentTime !== time) {\n var diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n dashInstance = _ref2.dashInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _libraryInstance = dashInstance || libraryInstance; // backwards comp;\n\n _videoElement = _libraryInstance.getVideoElement();\n\n if (!_libraryInstance) {\n room._log('No dash player instance!');\n\n return;\n }\n\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === 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 (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _libraryInstance.on('bufferStateChanged', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function 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\n if (_libraryInstance) {\n _libraryInstance.off('bufferStateChanged', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDashJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-dash.js?");
9204
+ 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\n\nvar syncDashJs = function syncDashJs() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var startSyncLoop = function 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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n realPosition = _calculateSyncDiffere.realPosition,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var buffering = function buffering(event) {\n if (event.mediaType === 'video' || event.mediaType === 'audio') {\n if (event.state === 'bufferStalled') {\n handleStalledWaiting();\n }\n }\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos, ping) {\n var seekRanges = _videoElement.buffered;\n var seekRange = {};\n\n for (var i = 0; i < seekRanges.length; i++) {\n var _c_start = seekRanges.start(i);\n\n var _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 var position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position: position,\n realPosition: position,\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,\n realPosition: position,\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,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPosition: position,\n isBufferSufficient: false\n };\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve, reject) {\n if (_videoElement.currentTime !== time) {\n var diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n dashInstance = _ref2.dashInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _libraryInstance = dashInstance || libraryInstance; // backwards comp;\n\n _videoElement = _libraryInstance.getVideoElement();\n\n if (!_libraryInstance) {\n room._log('No dash player instance!');\n\n return;\n }\n\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === 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 (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _libraryInstance.on('bufferStateChanged', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function 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\n if (_libraryInstance) {\n _libraryInstance.off('bufferStateChanged', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDashJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-dash.js?");
9205
9205
 
9206
9206
  /***/ }),
9207
9207
 
@@ -9213,7 +9213,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9213
9213
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9214
9214
 
9215
9215
  "use strict";
9216
- 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\n\nvar syncDaznDash = function syncDaznDash() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var startSyncLoop = function 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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n realPosition = _calculateSyncDiffere.realPosition,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos, ping) {\n var seekRanges = _videoElement.buffered;\n var seekRange = {};\n\n for (var i = 0; i < seekRanges.length; i++) {\n var _c_start = seekRanges.start(i);\n\n var _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 var position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position: position,\n realPostion: position,\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,\n realPostion: position,\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,\n realPostion: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPostion: position,\n isBufferSufficient: false\n };\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve, reject) {\n if (_videoElement.currentTime !== time) {\n var diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n }; // const seekTo = (time) => {\n // return new Promise((resolve, reject) => {\n // if(_videoElement.currentTime !== time) {\n // let __ = Date.now();\n // isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n // _videoElement.addEventListener('playing', () => {\n // room._log(`It took the player ${(Date.now() - __) / 1000} seconds to seek `);\n // isProgrammaticallySeeked = false;\n // resolve();\n // }, {once:true});\n // _videoElement.currentTime = time;\n // } else resolve()\n // });\n // };\n\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _libraryInstance = libraryInstance;\n _videoElement = _libraryInstance.videoElement;\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === 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 (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _libraryInstance.addEventListener('buffer', handleStalledWaiting);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function 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\n if (_libraryInstance) {\n _libraryInstance.removeEventListener('buffer', handleStalledWaiting);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDaznDash);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-dazn-dash.js?");
9216
+ 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\n\nvar syncDaznDash = function syncDaznDash() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var startSyncLoop = function 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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n realPosition = _calculateSyncDiffere.realPosition,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos, ping) {\n var seekRanges = _videoElement.buffered;\n var seekRange = {};\n\n for (var i = 0; i < seekRanges.length; i++) {\n var _c_start = seekRanges.start(i);\n\n var _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 var position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position: position,\n realPostion: position,\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,\n realPostion: position,\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,\n realPostion: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPostion: position,\n isBufferSufficient: false\n };\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve, reject) {\n if (_videoElement.currentTime !== time) {\n var diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n }; // const seekTo = (time) => {\n // return new Promise((resolve, reject) => {\n // if(_videoElement.currentTime !== time) {\n // let __ = Date.now();\n // isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n // _videoElement.addEventListener('playing', () => {\n // room._log(`It took the player ${(Date.now() - __) / 1000} seconds to seek `);\n // isProgrammaticallySeeked = false;\n // resolve();\n // }, {once:true});\n // _videoElement.currentTime = time;\n // } else resolve()\n // });\n // };\n\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _libraryInstance = libraryInstance;\n _videoElement = _libraryInstance.videoElement;\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === 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 (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _libraryInstance.addEventListener('buffer', handleStalledWaiting);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function 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\n if (_libraryInstance) {\n _libraryInstance.removeEventListener('buffer', handleStalledWaiting);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDaznDash);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-dazn-dash.js?");
9217
9217
 
9218
9218
  /***/ }),
9219
9219
 
@@ -9237,7 +9237,7 @@ eval("__webpack_require__.r(__webpack_exports__);\nfunction _objectDestructuring
9237
9237
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9238
9238
 
9239
9239
  "use strict";
9240
- 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\n\nvar syncDoris = function syncDoris() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n\n var startSyncLoop = function 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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n act = _calculateSyncDiffere.act,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\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) {\n return seekDoris(position, act).then(function () {\n var seekDuration = Date.now() - syncStartTime;\n\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos + seekDuration, syncData.ping),\n position = _calculateSyncDiffere2.position;\n\n var syncPrecision = Math.abs(position);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position;\n return (position = _libraryInstance.getCurrentDate()) === null || position === void 0 ? 0 : position.getTime();\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos) {\n var ping = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;\n\n var _pos;\n\n var currentTime = (_pos = _libraryInstance.getCurrentDate()) === null || _pos === void 0 ? null : _pos.getTime();\n\n if (currentTime && fragmentPos) {\n return {\n position: (fragmentPos + ping / 2 - currentTime) / 1000,\n act: fragmentPos + ping / 2,\n isBufferSufficient: true\n };\n } else {\n return {\n position: null,\n isBufferSufficient: false\n };\n }\n };\n\n var seekDoris = function seekDoris(time, act) {\n //https://mcorp.no/lib/mediasync.js\n return new Promise(function (resolve, reject) {\n if (time !== 0) {\n if (isSafari) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _libraryInstance.seekTo(new Date(act));\n } else {\n if (time > 0 && time < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n var diff = time; // _videoElement.addEventListener('waiting', __, {once:true});\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime += time;\n }\n }\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var sgtid = null;\n\n var stalledGenerator = function stalledGenerator() {\n clearTimeout(sgtid);\n sgtid = setTimeout(function () {\n if (_videoElement.paused === false) {\n handleStalledWaiting();\n }\n }, 1000);\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n dorisInstance = _ref2.dorisInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _libraryInstance = dorisInstance || libraryInstance;\n _videoElement = _libraryInstance.sourceHandler.getElement();\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === 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 (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _videoElement.addEventListener('timeupdate', stalledGenerator);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function 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\n if (_videoElement) {\n _videoElement.removeEventListener('timeupdate', stalledGenerator);\n\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDoris);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-doris.js?");
9240
+ 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\n\nvar syncDoris = function syncDoris() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n\n var startSyncLoop = function 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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n act = _calculateSyncDiffere.act,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\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) {\n return seekDoris(position, act).then(function () {\n var seekDuration = Date.now() - syncStartTime;\n\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos + seekDuration, syncData.ping),\n position = _calculateSyncDiffere2.position;\n\n var syncPrecision = Math.abs(position);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position;\n return (position = _libraryInstance.getCurrentDate()) === null || position === void 0 ? 0 : position.getTime();\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos) {\n var ping = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;\n\n var _pos;\n\n var currentTime = (_pos = _libraryInstance.getCurrentDate()) === null || _pos === void 0 ? null : _pos.getTime();\n\n if (currentTime && fragmentPos) {\n return {\n position: (fragmentPos + ping / 2 - currentTime) / 1000,\n act: fragmentPos + ping / 2,\n isBufferSufficient: true\n };\n } else {\n return {\n position: null,\n isBufferSufficient: false\n };\n }\n };\n\n var seekDoris = function seekDoris(time, act) {\n //https://mcorp.no/lib/mediasync.js\n return new Promise(function (resolve, reject) {\n if (time !== 0) {\n if (isSafari) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _libraryInstance.seekTo(new Date(act));\n } else {\n if (time > 0 && time < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n var diff = time; // _videoElement.addEventListener('waiting', __, {once:true});\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime += time;\n }\n }\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var sgtid = null;\n\n var stalledGenerator = function stalledGenerator() {\n clearTimeout(sgtid);\n sgtid = setTimeout(function () {\n if (_videoElement.paused === false) {\n handleStalledWaiting();\n }\n }, 1000);\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n dorisInstance = _ref2.dorisInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _libraryInstance = dorisInstance || libraryInstance;\n _videoElement = _libraryInstance.sourceHandler.getElement();\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === 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 (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _videoElement.addEventListener('timeupdate', stalledGenerator);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function 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\n if (_videoElement) {\n _videoElement.removeEventListener('timeupdate', stalledGenerator);\n\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDoris);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-doris.js?");
9241
9241
 
9242
9242
  /***/ }),
9243
9243
 
@@ -9249,7 +9249,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9249
9249
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9250
9250
 
9251
9251
  "use strict";
9252
- 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\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\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\n\nvar syncVodHlsJs = function syncVodHlsJs() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var _roomId = null;\n var _syncDisabled = false;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var seekingDebounceId = null;\n var seekingDebounceTimeout = 300;\n var isPlaying = false;\n var isProgrammaticallySeeked = false;\n var isForcedMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (_syncDisabled) {\n room._log('--- Sync loop will not start due to sync force disabled ---');\n\n return;\n }\n\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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (syncData.masterFragmentSn) {\n playMedia();\n } else {\n pauseMedia();\n }\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(position + (isPlaying ? seekDuration : 0) - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement) {\n //TODO: shit fix ... data channel with other participant is not opened yet so we wait\n setTimeout(function () {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }, 1000);\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var handleRemoveRemoteParticipant = function handleRemoveRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var buffering = function buffering(event) {\n var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n if (data.details === 'bufferStalledError') {\n handleStalledWaiting();\n }\n };\n\n var executePlayerIotEvents = function executePlayerIotEvents(data) {\n var rid = _roomId || room.roomId;\n\n if (data.attributeName === 'playerReplay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n seekTo(0).then(function () {\n return playMedia();\n });\n }\n\n if (data.attributeName === 'playerPlay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n playMedia();\n }\n\n if (data.attributeName === 'playerPause' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n pauseMedia();\n }\n };\n\n var parseIotEvents = function parseIotEvents(data) {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(function (event) {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents(_objectSpread(_objectSpread({}, event), {}, {\n roomId: data.roomId,\n userId: data.userId\n }));\n }\n });\n }\n\n if (data.operation === 'sendMessage') {\n executePlayerIotEvents(data);\n }\n }\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n } else if (msg.videoroom === 'message') {\n // ignoring non studio commands if master\n if (isForcedMaster && msg.from !== null) {\n return;\n }\n\n if (_syncDisabled) {\n return;\n }\n\n if (msg.user_action === 'sync_seeking') {\n seekMedia(msg).catch(function () {});\n } else if (msg.user_action === 'sync_seeked') {} else if (msg.user_action === 'sync_play' || msg.action === 'sync_play') {\n playMedia();\n } else if (msg.user_action === 'sync_pause' || msg.action === 'sync_pause') {\n pauseMedia();\n }\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn) {\n var fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n var seekMedia = function seekMedia(msg) {\n msg = _objectSpread({\n userId: msg.from\n }, msg.text && JSON.parse(msg.text));\n\n if (msg.handleId !== room.handleId) {\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0),\n position = _calculateSyncDiffere2.position,\n isBufferSufficient = _calculateSyncDiffere2.isBufferSufficient; //TODO: right ping\n\n\n if (position) {\n return seekTo(position).then(function () {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n var prePlay = function prePlay() {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n var wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(function () {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(function () {\n return true;\n }).finally(function () {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n var playMedia = function playMedia() {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(function () {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n var pauseMedia = function pauseMedia() {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', function () {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve) {\n if (_videoElement.currentTime !== time) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('seeked', function () {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(function () {});\n }\n };\n\n var handleSeeking = function handleSeeking() {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(function () {\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n roomSession.sendSystemMessage('sync_seeking', {\n timestamp: new Date().getTime(),\n handleId: room.handleId,\n fragment: \"0\",\n //isPlaying ? \"1\":\"0\",\n fragment_pos: Number(fragmentPosition)\n }, undefined, null).catch(function () {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n var handleSeeked = function handleSeeked() {};\n\n var handleEnded = function handleEnded() {};\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n hlsInstance = _ref2.hlsInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster,\n _ref2$isStudio = _ref2.isStudio,\n isStudio = _ref2$isStudio === void 0 ? false : _ref2$isStudio,\n roomId = _ref2.roomId,\n syncDisabled = _ref2.syncDisabled;\n\n _libraryInstance = hlsInstance || libraryInstance; // backwards comp;\n\n _videoElement = _libraryInstance.media;\n _roomId = roomId;\n _syncDisabled = syncDisabled;\n\n if (!_libraryInstance) {\n room._log('No hls.js player instance!');\n\n return;\n }\n\n emitter.emit('playerSyncing', false);\n isForcedMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.on('data', parseDataEvents);\n wt.iot.$on('message', parseIotEvents);\n\n if (isForcedMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_libraryInstance && _videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(function () {\n _libraryInstance.on('hlsError', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n\n _videoElement.addEventListener('seeking', handleSeeking);\n\n _videoElement.addEventListener('seeked', handleSeeked);\n\n _videoElement.addEventListener('ended', handleEnded);\n\n startSyncLoop();\n });\n }\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_libraryInstance) {\n _libraryInstance.off('hlsError', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _libraryInstance = null;\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodHlsJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-hls-vod.js?");
9252
+ 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\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\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\n\nvar syncVodHlsJs = function syncVodHlsJs() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var _roomId = null;\n var _syncDisabled = false;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var seekingDebounceId = null;\n var seekingDebounceTimeout = 300;\n var isPlaying = false;\n var isProgrammaticallySeeked = false;\n var isForcedMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (_syncDisabled) {\n room._log('--- Sync loop will not start due to sync force disabled ---');\n\n return;\n }\n\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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (syncData.masterFragmentSn) {\n playMedia();\n } else {\n pauseMedia();\n }\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(position + (isPlaying ? seekDuration : 0) - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement) {\n //TODO: shit fix ... data channel with other participant is not opened yet so we wait\n setTimeout(function () {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }, 1000);\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var handleRemoveRemoteParticipant = function handleRemoveRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var buffering = function buffering(event) {\n var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n if (data.details === 'bufferStalledError') {\n handleStalledWaiting();\n }\n };\n\n var executePlayerIotEvents = function executePlayerIotEvents(data) {\n var rid = _roomId || room.roomId;\n\n if (data.attributeName === 'playerReplay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n seekTo(0).then(function () {\n return playMedia();\n });\n }\n\n if (data.attributeName === 'playerPlay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n playMedia();\n }\n\n if (data.attributeName === 'playerPause' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n pauseMedia();\n }\n };\n\n var parseIotEvents = function parseIotEvents(data) {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(function (event) {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents(_objectSpread(_objectSpread({}, event), {}, {\n roomId: data.roomId,\n userId: data.userId\n }));\n }\n });\n }\n\n if (data.operation === 'sendMessage') {\n executePlayerIotEvents(data);\n }\n }\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n } else if (msg.videoroom === 'message') {\n // ignoring non studio commands if master\n if (isForcedMaster && msg.from !== null) {\n return;\n }\n\n if (_syncDisabled) {\n return;\n }\n\n if (msg.user_action === 'sync_seeking') {\n seekMedia(msg).catch(function () {});\n } else if (msg.user_action === 'sync_seeked') {} else if (msg.user_action === 'sync_play' || msg.action === 'sync_play') {\n playMedia();\n } else if (msg.user_action === 'sync_pause' || msg.action === 'sync_pause') {\n pauseMedia();\n }\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn) {\n var fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n var seekMedia = function seekMedia(msg) {\n msg = _objectSpread({\n userId: msg.from\n }, msg.text && JSON.parse(msg.text));\n\n if (msg.handleId !== room.handleId) {\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0),\n position = _calculateSyncDiffere2.position,\n isBufferSufficient = _calculateSyncDiffere2.isBufferSufficient; //TODO: right ping\n\n\n if (position) {\n return seekTo(position).then(function () {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n var prePlay = function prePlay() {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n var wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(function () {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(function () {\n return true;\n }).finally(function () {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n var playMedia = function playMedia() {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(function () {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n var pauseMedia = function pauseMedia() {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', function () {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve) {\n if (_videoElement.currentTime !== time) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('seeked', function () {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(function () {});\n }\n };\n\n var handleSeeking = function handleSeeking() {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(function () {\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n roomSession.sendSystemMessage('sync_seeking', {\n timestamp: new Date().getTime(),\n handleId: room.handleId,\n fragment: \"0\",\n //isPlaying ? \"1\":\"0\",\n fragment_pos: Number(fragmentPosition)\n }, undefined, null).catch(function () {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n var handleSeeked = function handleSeeked() {};\n\n var handleEnded = function handleEnded() {};\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n hlsInstance = _ref2.hlsInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster,\n _ref2$isStudio = _ref2.isStudio,\n isStudio = _ref2$isStudio === void 0 ? false : _ref2$isStudio,\n roomId = _ref2.roomId,\n syncDisabled = _ref2.syncDisabled;\n\n _libraryInstance = hlsInstance || libraryInstance; // backwards comp;\n\n _videoElement = _libraryInstance.media;\n _roomId = roomId;\n _syncDisabled = syncDisabled;\n\n if (!_libraryInstance) {\n room._log('No hls.js player instance!');\n\n return;\n }\n\n emitter.emit('playerSyncing', false);\n isForcedMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.on('data', parseDataEvents);\n wt.iot.$on('message', parseIotEvents);\n\n if (isForcedMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_libraryInstance && _videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(function () {\n _libraryInstance.on('hlsError', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n\n _videoElement.addEventListener('seeking', handleSeeking);\n\n _videoElement.addEventListener('seeked', handleSeeked);\n\n _videoElement.addEventListener('ended', handleEnded);\n\n startSyncLoop();\n });\n }\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_libraryInstance) {\n _libraryInstance.off('hlsError', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _libraryInstance = null;\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodHlsJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-hls-vod.js?");
9253
9253
 
9254
9254
  /***/ }),
9255
9255
 
@@ -9261,7 +9261,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9261
9261
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9262
9262
 
9263
9263
  "use strict";
9264
- 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/*\n * TODO:\n * Sync we get\n * machineTimestamp = now\n * ping = (endRequestTimestamp - startRequestTimestamp) / 2\n * clockDifference = (serverTimestamp - machineTimestamp - ping)\n *\n *\n * usable vars : (now +- clockDifference) === currentServerTimestamp ---> when event was received\n * : (otherMachineTimestamp +- otherMachineClockDifference) === currentServerTimestamp ---> when event was sent\n *\n *\n * ping: (this user currentServerTimestamp a.k.a when event was received) - (remote user currentServerTimestamp a.k.a. when event was sent )\n *\n *\n * */\n\n\nvar syncHlsJs = function syncHlsJs() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var currentFragmentSn = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var startSyncLoop = function 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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\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) {\n return seekBy(position).then(function () {\n var seekDuration = Date.now() - syncStartTime;\n\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos + seekDuration, syncData.ping),\n position = _calculateSyncDiffere2.position,\n isBufferSufficient = _calculateSyncDiffere2.isBufferSufficient;\n\n var syncPrecision = Math.abs(position);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration / 1000));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var buffering = function buffering(event) {\n var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n if (data.details === 'bufferStalledError') {\n handleStalledWaiting();\n }\n };\n\n var hlsFragChanged = function hlsFragChanged(event, data) {\n currentFragmentSn = data.frag.sn;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var _currentFragment$body;\n\n var fragments = _libraryInstance.streamController.fragmentTracker.fragments;\n\n if (!fragments) {\n return 0;\n }\n\n var currentFragment = fragments[Object.keys(fragments).find(function (key) {\n return key.indexOf(currentFragmentSn) > -1;\n })];\n\n if (!currentFragment) {\n return 0;\n }\n\n return Math.max((_libraryInstance.streamController.lastCurrentTime - (((_currentFragment$body = currentFragment.body) === null || _currentFragment$body === void 0 ? void 0 : _currentFragment$body.startPTS) || 0)) * 1000, 0);\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(masterFragmentSn, masterFragmentPos, ping) {\n var _currentFragment$body2;\n\n var fragments = _libraryInstance.streamController.fragmentTracker.fragments;\n var fragmentNumbers = Object.keys(fragments).map(function (key) {\n return parseInt(key.slice(key.lastIndexOf('_') + 1));\n }).sort(function (a, b) {\n return a - b;\n }); // our position in fragment\n //let currentFragmentSn = currentFragmentSn;\n\n var currentFragment = fragments[Object.keys(fragments).find(function (key) {\n return key.indexOf(currentFragmentSn) > -1;\n })];\n\n if (!currentFragment) {\n room._log('Current fragment not found, what now?', currentFragmentSn);\n\n return {\n position: null,\n isBufferSufficient: false\n };\n }\n\n var currentFragmentPos = Math.max((_libraryInstance.streamController.lastCurrentTime - (((_currentFragment$body2 = currentFragment.body) === null || _currentFragment$body2 === void 0 ? void 0 : _currentFragment$body2.startPTS) || 0)) * 1000, 0);\n var currentFragmentLength = currentFragment.body.duration * 1000;\n\n room._log(\"Our current fragment is: \".concat(currentFragmentSn));\n\n room._log(\"Our current fragment position is: \".concat(currentFragmentPos));\n\n room._log(\"Our current fragment length is: \".concat(currentFragmentLength)); // real server fragment\n\n\n var realMasterFragmentSn = masterFragmentSn; // real server position in fragment\n\n var realMasterFragmentPos = Math.max(ping / 2 + masterFragmentPos, 0); // simple flag\n\n var isBufferSufficient = false;\n /* Searching for fragment and in-fragment position when taking all delays into account */\n\n var relevantFragmentNumbers = fragmentNumbers.indexOf(masterFragmentSn) > -1 ? fragmentNumbers.slice(fragmentNumbers.indexOf(masterFragmentSn)) : [];\n\n var _loop = function _loop(i, len) {\n var sn = relevantFragmentNumbers[i];\n var fragment = fragments[Object.keys(fragments).find(function (key) {\n return key.indexOf(sn) > -1;\n })];\n var fragmentDuration = fragment.body.duration * 1000;\n\n room._log(\"Correction diff: \".concat(realMasterFragmentPos - fragmentDuration));\n\n realMasterFragmentSn = sn;\n\n if (realMasterFragmentPos - fragmentDuration > 0) {\n room._log(\"Not enough at fragment \".concat(sn));\n\n realMasterFragmentPos -= fragmentDuration;\n } else {\n room._log(\"Enough at fragment \".concat(sn));\n\n isBufferSufficient = true;\n return \"break\";\n }\n };\n\n for (var i = 0, len = relevantFragmentNumbers.length; i < len; i++) {\n var _ret = _loop(i, len);\n\n if (_ret === \"break\") break;\n } // We're not ready yet\n\n\n if (!isBufferSufficient) {\n room._log(\"We don't have required fragment \".concat(realMasterFragmentSn, \" yet\"));\n\n return {\n position: null,\n isBufferSufficient: false\n };\n } // We are too ahead\n\n\n if (realMasterFragmentSn < currentFragmentSn) {\n room._log(\"We are ahead of master...\");\n\n room._log(\"Real master fragment: \".concat(realMasterFragmentSn));\n\n room._log(\"Our fragment: \".concat(currentFragmentSn));\n\n var seekTime = currentFragmentPos - realMasterFragmentPos;\n\n var _relevantFragmentNumbers = fragmentNumbers.slice(fragmentNumbers.indexOf(realMasterFragmentSn));\n\n var _loop2 = function _loop2(_i, _len) {\n var sn = _relevantFragmentNumbers[_i];\n var fragment = fragments[Object.keys(fragments).find(function (key) {\n return key.indexOf(sn) > -1;\n })];\n var fragmentDuration = fragment.body.duration * 1000;\n\n if (sn >= currentFragmentSn) {\n return \"break\";\n }\n\n seekTime += fragmentDuration;\n };\n\n for (var _i = 0, _len = _relevantFragmentNumbers.length; _i < _len; _i++) {\n var _ret2 = _loop2(_i, _len);\n\n if (_ret2 === \"break\") break;\n }\n\n room._log(\"Sync difference is: \".concat(seekTime));\n\n return {\n position: seekTime / 1000 * -1,\n isBufferSufficient: true\n };\n } // We are behind or spot on\n else {\n room._log(\"We're behind or spot on master...\");\n\n room._log(\"Real master fragment: \".concat(realMasterFragmentSn));\n\n room._log(\"Our fragment: \".concat(currentFragmentSn));\n\n var _seekTime = realMasterFragmentPos - currentFragmentPos;\n\n var _relevantFragmentNumbers2 = fragmentNumbers.slice(fragmentNumbers.indexOf(currentFragmentSn));\n\n var _loop3 = function _loop3(_i2, _len2) {\n var sn = _relevantFragmentNumbers2[_i2];\n var fragment = fragments[Object.keys(fragments).find(function (key) {\n return key.indexOf(sn) > -1;\n })];\n var fragmentDuration = fragment.body.duration * 1000;\n\n if (sn >= realMasterFragmentSn) {\n return \"break\";\n }\n\n _seekTime += fragmentDuration;\n };\n\n for (var _i2 = 0, _len2 = _relevantFragmentNumbers2.length; _i2 < _len2; _i2++) {\n var _ret3 = _loop3(_i2, _len2);\n\n if (_ret3 === \"break\") break;\n }\n\n room._log(\"We can proceed with seek time: \".concat(_seekTime));\n\n return {\n position: _seekTime / 1000,\n isBufferSufficient: true\n };\n }\n };\n\n var seekBy = function seekBy(time) {\n //https://mcorp.no/lib/mediasync.js\n return new Promise(function (resolve, reject) {\n if (time !== 0) {\n if (time > 0 && time < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n var diff = time; // _videoElement.addEventListener('waiting', __, {once:true});\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime += time;\n }\n } else resolve();\n });\n };\n\n var seekTo = function seekTo(time) {\n //https://webtiming.github.io/timingsrc/ use this\n //https://mcorp.no/lib/mediasync.js\n return new Promise(function (resolve, reject) {\n if (_videoElement.currentTime !== time) {\n var diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _2 = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _2) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\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 fragment = currentFragmentSn;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Fragment: \".concat(fragment));\n\n room._log(\"Fragment position: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(fragment),\n fragment_pos: Number(fragmentPosition),\n slave_id: Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragment = currentFragmentSn;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(fragment),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n hlsInstance = _ref2.hlsInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _libraryInstance = hlsInstance || libraryInstance; // backwards comp;\n\n _videoElement = _libraryInstance.media;\n\n if (!_libraryInstance) {\n room._log('No hls.js player instance!');\n\n return;\n }\n\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === 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 (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _libraryInstance.once('hlsFragChanged', function () {\n restartSyncLoop();\n });\n }\n\n _libraryInstance.on('hlsError', buffering);\n\n _libraryInstance.on('hlsFragChanged', hlsFragChanged);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function 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\n if (_libraryInstance) {\n _libraryInstance.off('hlsError', buffering);\n\n _libraryInstance.off('hlsFragChanged', hlsFragChanged);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncHlsJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-hls.js?");
9264
+ 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/*\n * TODO:\n * Sync we get\n * machineTimestamp = now\n * ping = (endRequestTimestamp - startRequestTimestamp) / 2\n * clockDifference = (serverTimestamp - machineTimestamp - ping)\n *\n *\n * usable vars : (now +- clockDifference) === currentServerTimestamp ---> when event was received\n * : (otherMachineTimestamp +- otherMachineClockDifference) === currentServerTimestamp ---> when event was sent\n *\n *\n * ping: (this user currentServerTimestamp a.k.a when event was received) - (remote user currentServerTimestamp a.k.a. when event was sent )\n *\n *\n * */\n\n\nvar syncHlsJs = function syncHlsJs() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var currentFragmentSn = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var startSyncLoop = function 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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\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) {\n return seekBy(position).then(function () {\n var seekDuration = Date.now() - syncStartTime;\n\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos + seekDuration, syncData.ping),\n position = _calculateSyncDiffere2.position,\n isBufferSufficient = _calculateSyncDiffere2.isBufferSufficient;\n\n var syncPrecision = Math.abs(position);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration / 1000));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var buffering = function buffering(event) {\n var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n if (data.details === 'bufferStalledError') {\n handleStalledWaiting();\n }\n };\n\n var hlsFragChanged = function hlsFragChanged(event, data) {\n currentFragmentSn = data.frag.sn;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var _currentFragment$body;\n\n var fragments = _libraryInstance.streamController.fragmentTracker.fragments;\n\n if (!fragments) {\n return 0;\n }\n\n var currentFragment = fragments[Object.keys(fragments).find(function (key) {\n return key.indexOf(currentFragmentSn) > -1;\n })];\n\n if (!currentFragment) {\n return 0;\n }\n\n return Math.max((_libraryInstance.streamController.lastCurrentTime - (((_currentFragment$body = currentFragment.body) === null || _currentFragment$body === void 0 ? void 0 : _currentFragment$body.startPTS) || 0)) * 1000, 0);\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(masterFragmentSn, masterFragmentPos, ping) {\n var _currentFragment$body2;\n\n var fragments = _libraryInstance.streamController.fragmentTracker.fragments;\n var fragmentNumbers = Object.keys(fragments).map(function (key) {\n return parseInt(key.slice(key.lastIndexOf('_') + 1));\n }).sort(function (a, b) {\n return a - b;\n }); // our position in fragment\n //let currentFragmentSn = currentFragmentSn;\n\n var currentFragment = fragments[Object.keys(fragments).find(function (key) {\n return key.indexOf(currentFragmentSn) > -1;\n })];\n\n if (!currentFragment) {\n room._log('Current fragment not found, what now?', currentFragmentSn);\n\n return {\n position: null,\n isBufferSufficient: false\n };\n }\n\n var currentFragmentPos = Math.max((_libraryInstance.streamController.lastCurrentTime - (((_currentFragment$body2 = currentFragment.body) === null || _currentFragment$body2 === void 0 ? void 0 : _currentFragment$body2.startPTS) || 0)) * 1000, 0);\n var currentFragmentLength = currentFragment.body.duration * 1000;\n\n room._log(\"Our current fragment is: \".concat(currentFragmentSn));\n\n room._log(\"Our current fragment position is: \".concat(currentFragmentPos));\n\n room._log(\"Our current fragment length is: \".concat(currentFragmentLength)); // real server fragment\n\n\n var realMasterFragmentSn = masterFragmentSn; // real server position in fragment\n\n var realMasterFragmentPos = Math.max(ping / 2 + masterFragmentPos, 0); // simple flag\n\n var isBufferSufficient = false;\n /* Searching for fragment and in-fragment position when taking all delays into account */\n\n var relevantFragmentNumbers = fragmentNumbers.indexOf(masterFragmentSn) > -1 ? fragmentNumbers.slice(fragmentNumbers.indexOf(masterFragmentSn)) : [];\n\n var _loop = function _loop(i, len) {\n var sn = relevantFragmentNumbers[i];\n var fragment = fragments[Object.keys(fragments).find(function (key) {\n return key.indexOf(sn) > -1;\n })];\n var fragmentDuration = fragment.body.duration * 1000;\n\n room._log(\"Correction diff: \".concat(realMasterFragmentPos - fragmentDuration));\n\n realMasterFragmentSn = sn;\n\n if (realMasterFragmentPos - fragmentDuration > 0) {\n room._log(\"Not enough at fragment \".concat(sn));\n\n realMasterFragmentPos -= fragmentDuration;\n } else {\n room._log(\"Enough at fragment \".concat(sn));\n\n isBufferSufficient = true;\n return \"break\";\n }\n };\n\n for (var i = 0, len = relevantFragmentNumbers.length; i < len; i++) {\n var _ret = _loop(i, len);\n\n if (_ret === \"break\") break;\n } // We're not ready yet\n\n\n if (!isBufferSufficient) {\n room._log(\"We don't have required fragment \".concat(realMasterFragmentSn, \" yet\"));\n\n return {\n position: null,\n isBufferSufficient: false\n };\n } // We are too ahead\n\n\n if (realMasterFragmentSn < currentFragmentSn) {\n room._log(\"We are ahead of master...\");\n\n room._log(\"Real master fragment: \".concat(realMasterFragmentSn));\n\n room._log(\"Our fragment: \".concat(currentFragmentSn));\n\n var seekTime = currentFragmentPos - realMasterFragmentPos;\n\n var _relevantFragmentNumbers = fragmentNumbers.slice(fragmentNumbers.indexOf(realMasterFragmentSn));\n\n var _loop2 = function _loop2(_i, _len) {\n var sn = _relevantFragmentNumbers[_i];\n var fragment = fragments[Object.keys(fragments).find(function (key) {\n return key.indexOf(sn) > -1;\n })];\n var fragmentDuration = fragment.body.duration * 1000;\n\n if (sn >= currentFragmentSn) {\n return \"break\";\n }\n\n seekTime += fragmentDuration;\n };\n\n for (var _i = 0, _len = _relevantFragmentNumbers.length; _i < _len; _i++) {\n var _ret2 = _loop2(_i, _len);\n\n if (_ret2 === \"break\") break;\n }\n\n room._log(\"Sync difference is: \".concat(seekTime));\n\n return {\n position: seekTime / 1000 * -1,\n isBufferSufficient: true\n };\n } // We are behind or spot on\n else {\n room._log(\"We're behind or spot on master...\");\n\n room._log(\"Real master fragment: \".concat(realMasterFragmentSn));\n\n room._log(\"Our fragment: \".concat(currentFragmentSn));\n\n var _seekTime = realMasterFragmentPos - currentFragmentPos;\n\n var _relevantFragmentNumbers2 = fragmentNumbers.slice(fragmentNumbers.indexOf(currentFragmentSn));\n\n var _loop3 = function _loop3(_i2, _len2) {\n var sn = _relevantFragmentNumbers2[_i2];\n var fragment = fragments[Object.keys(fragments).find(function (key) {\n return key.indexOf(sn) > -1;\n })];\n var fragmentDuration = fragment.body.duration * 1000;\n\n if (sn >= realMasterFragmentSn) {\n return \"break\";\n }\n\n _seekTime += fragmentDuration;\n };\n\n for (var _i2 = 0, _len2 = _relevantFragmentNumbers2.length; _i2 < _len2; _i2++) {\n var _ret3 = _loop3(_i2, _len2);\n\n if (_ret3 === \"break\") break;\n }\n\n room._log(\"We can proceed with seek time: \".concat(_seekTime));\n\n return {\n position: _seekTime / 1000,\n isBufferSufficient: true\n };\n }\n };\n\n var seekBy = function seekBy(time) {\n //https://mcorp.no/lib/mediasync.js\n return new Promise(function (resolve, reject) {\n if (time !== 0) {\n if (time > 0 && time < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n var diff = time; // _videoElement.addEventListener('waiting', __, {once:true});\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime += time;\n }\n } else resolve();\n });\n };\n\n var seekTo = function seekTo(time) {\n //https://webtiming.github.io/timingsrc/ use this\n //https://mcorp.no/lib/mediasync.js\n return new Promise(function (resolve, reject) {\n if (_videoElement.currentTime !== time) {\n var diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _2 = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _2) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\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 fragment = currentFragmentSn;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Fragment: \".concat(fragment));\n\n room._log(\"Fragment position: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(fragment),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragment = currentFragmentSn;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(fragment),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n hlsInstance = _ref2.hlsInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _libraryInstance = hlsInstance || libraryInstance; // backwards comp;\n\n _videoElement = _libraryInstance.media;\n\n if (!_libraryInstance) {\n room._log('No hls.js player instance!');\n\n return;\n }\n\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === 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 (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _libraryInstance.once('hlsFragChanged', function () {\n restartSyncLoop();\n });\n }\n\n _libraryInstance.on('hlsError', buffering);\n\n _libraryInstance.on('hlsFragChanged', hlsFragChanged);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function 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\n if (_libraryInstance) {\n _libraryInstance.off('hlsError', buffering);\n\n _libraryInstance.off('hlsFragChanged', hlsFragChanged);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncHlsJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-hls.js?");
9265
9265
 
9266
9266
  /***/ }),
9267
9267
 
@@ -9273,7 +9273,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9273
9273
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9274
9274
 
9275
9275
  "use strict";
9276
- 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\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\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\n\nvar syncVodHlsJs = function syncVodHlsJs() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _videoElement = null;\n var _roomId = null;\n var _syncDisabled = false;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var seekingDebounceId = null;\n var seekingDebounceTimeout = 300;\n var isPlaying = false;\n var isProgrammaticallySeeked = false;\n var isForcedMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (_syncDisabled) {\n room._log('--- Sync loop will not start due to sync force disabled ---');\n\n return;\n }\n\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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (syncData.masterFragmentSn) {\n playMedia();\n } else {\n pauseMedia();\n }\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(position + (isPlaying ? seekDuration : 0) - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement) {\n //TODO: shit fix ... data channel with other participant is not opened yet so we wait\n setTimeout(function () {\n restartSyncLoop();\n }, 1000);\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var handleRemoveRemoteParticipant = function handleRemoveRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var executePlayerIotEvents = function executePlayerIotEvents(data) {\n var rid = _roomId || room.roomId;\n\n if (data.attributeName === 'playerReplay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n seekTo(0).then(function () {\n return playMedia();\n });\n }\n\n if (data.attributeName === 'playerPlay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n playMedia();\n }\n\n if (data.attributeName === 'playerPause' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n pauseMedia();\n }\n };\n\n var parseIotEvents = function parseIotEvents(data) {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(function (event) {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents(_objectSpread(_objectSpread({}, event), {}, {\n roomId: data.roomId,\n userId: data.userId\n }));\n }\n });\n }\n\n if (data.operation === 'sendMessage') {\n executePlayerIotEvents(data);\n }\n }\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n } else if (msg.videoroom === 'message') {\n // ignoring non studio commands if master\n if (isForcedMaster && msg.from !== null) {\n return;\n }\n\n if (_syncDisabled) {\n return;\n }\n\n if (msg.user_action === 'sync_seeking') {\n seekMedia(msg).catch(function () {});\n } else if (msg.user_action === 'sync_seeked') {} else if (msg.user_action === 'sync_play' || msg.action === 'sync_play') {\n playMedia();\n } else if (msg.user_action === 'sync_pause' || msg.action === 'sync_pause') {\n pauseMedia();\n }\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn) {\n var fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n var seekMedia = function seekMedia(msg) {\n msg = _objectSpread({\n userId: msg.from\n }, msg.text && JSON.parse(msg.text));\n\n if (msg.handleId !== room.handleId) {\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0),\n position = _calculateSyncDiffere2.position,\n isBufferSufficient = _calculateSyncDiffere2.isBufferSufficient; //TODO: right ping\n\n\n if (position) {\n return seekTo(position).then(function () {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n var prePlay = function prePlay() {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n var wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(function () {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(function () {\n return true;\n }).finally(function () {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n var playMedia = function playMedia() {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(function () {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n var pauseMedia = function pauseMedia() {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', function () {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve) {\n if (_videoElement.currentTime !== time) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('seeked', function () {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(function () {});\n }\n };\n\n var handleSeeking = function handleSeeking() {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(function () {\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n roomSession.sendSystemMessage('sync_seeking', {\n timestamp: new Date().getTime(),\n handleId: room.handleId,\n fragment: \"0\",\n //isPlaying ? \"1\":\"0\",\n fragment_pos: Number(fragmentPosition)\n }, undefined, null).catch(function () {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n var handleSeeked = function handleSeeked() {};\n\n var handleEnded = function handleEnded() {};\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n videoElement = _ref2.videoElement,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster,\n _ref2$isStudio = _ref2.isStudio,\n isStudio = _ref2$isStudio === void 0 ? false : _ref2$isStudio,\n roomId = _ref2.roomId,\n syncDisabled = _ref2.syncDisabled;\n\n _videoElement = videoElement;\n _roomId = roomId;\n _syncDisabled = syncDisabled;\n\n if (!_videoElement) {\n room._log('No video element present!');\n\n return;\n }\n\n emitter.emit('playerSyncing', false);\n isForcedMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.on('data', parseDataEvents);\n wt.iot.$on('message', parseIotEvents);\n\n if (isForcedMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(function () {\n _videoElement.addEventListener('stalled', handleStalledWaiting);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n\n _videoElement.addEventListener('seeking', handleSeeking);\n\n _videoElement.addEventListener('seeked', handleSeeked);\n\n _videoElement.addEventListener('ended', handleEnded);\n\n startSyncLoop();\n });\n }\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_videoElement) {\n _videoElement.removeEventListener('stalled', handleStalledWaiting);\n\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodHlsJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-native-hls-vod.js?");
9276
+ 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\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\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\n\nvar syncVodHlsJs = function syncVodHlsJs() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _videoElement = null;\n var _roomId = null;\n var _syncDisabled = false;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var seekingDebounceId = null;\n var seekingDebounceTimeout = 300;\n var isPlaying = false;\n var isProgrammaticallySeeked = false;\n var isForcedMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (_syncDisabled) {\n room._log('--- Sync loop will not start due to sync force disabled ---');\n\n return;\n }\n\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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (syncData.masterFragmentSn) {\n playMedia();\n } else {\n pauseMedia();\n }\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(position + (isPlaying ? seekDuration : 0) - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement) {\n //TODO: shit fix ... data channel with other participant is not opened yet so we wait\n setTimeout(function () {\n restartSyncLoop();\n }, 1000);\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var handleRemoveRemoteParticipant = function handleRemoveRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var executePlayerIotEvents = function executePlayerIotEvents(data) {\n var rid = _roomId || room.roomId;\n\n if (data.attributeName === 'playerReplay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n seekTo(0).then(function () {\n return playMedia();\n });\n }\n\n if (data.attributeName === 'playerPlay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n playMedia();\n }\n\n if (data.attributeName === 'playerPause' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n pauseMedia();\n }\n };\n\n var parseIotEvents = function parseIotEvents(data) {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(function (event) {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents(_objectSpread(_objectSpread({}, event), {}, {\n roomId: data.roomId,\n userId: data.userId\n }));\n }\n });\n }\n\n if (data.operation === 'sendMessage') {\n executePlayerIotEvents(data);\n }\n }\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n } else if (msg.videoroom === 'message') {\n // ignoring non studio commands if master\n if (isForcedMaster && msg.from !== null) {\n return;\n }\n\n if (_syncDisabled) {\n return;\n }\n\n if (msg.user_action === 'sync_seeking') {\n seekMedia(msg).catch(function () {});\n } else if (msg.user_action === 'sync_seeked') {} else if (msg.user_action === 'sync_play' || msg.action === 'sync_play') {\n playMedia();\n } else if (msg.user_action === 'sync_pause' || msg.action === 'sync_pause') {\n pauseMedia();\n }\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn) {\n var fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n var seekMedia = function seekMedia(msg) {\n msg = _objectSpread({\n userId: msg.from\n }, msg.text && JSON.parse(msg.text));\n\n if (msg.handleId !== room.handleId) {\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0),\n position = _calculateSyncDiffere2.position,\n isBufferSufficient = _calculateSyncDiffere2.isBufferSufficient; //TODO: right ping\n\n\n if (position) {\n return seekTo(position).then(function () {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n var prePlay = function prePlay() {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n var wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(function () {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(function () {\n return true;\n }).finally(function () {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n var playMedia = function playMedia() {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(function () {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n var pauseMedia = function pauseMedia() {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', function () {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve) {\n if (_videoElement.currentTime !== time) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('seeked', function () {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(function () {});\n }\n };\n\n var handleSeeking = function handleSeeking() {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(function () {\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n roomSession.sendSystemMessage('sync_seeking', {\n timestamp: new Date().getTime(),\n handleId: room.handleId,\n fragment: \"0\",\n //isPlaying ? \"1\":\"0\",\n fragment_pos: Number(fragmentPosition)\n }, undefined, null).catch(function () {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n var handleSeeked = function handleSeeked() {};\n\n var handleEnded = function handleEnded() {};\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n videoElement = _ref2.videoElement,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster,\n _ref2$isStudio = _ref2.isStudio,\n isStudio = _ref2$isStudio === void 0 ? false : _ref2$isStudio,\n roomId = _ref2.roomId,\n syncDisabled = _ref2.syncDisabled;\n\n _videoElement = videoElement;\n _roomId = roomId;\n _syncDisabled = syncDisabled;\n\n if (!_videoElement) {\n room._log('No video element present!');\n\n return;\n }\n\n emitter.emit('playerSyncing', false);\n isForcedMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.on('data', parseDataEvents);\n wt.iot.$on('message', parseIotEvents);\n\n if (isForcedMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(function () {\n _videoElement.addEventListener('stalled', handleStalledWaiting);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n\n _videoElement.addEventListener('seeking', handleSeeking);\n\n _videoElement.addEventListener('seeked', handleSeeked);\n\n _videoElement.addEventListener('ended', handleEnded);\n\n startSyncLoop();\n });\n }\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_videoElement) {\n _videoElement.removeEventListener('stalled', handleStalledWaiting);\n\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodHlsJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-native-hls-vod.js?");
9277
9277
 
9278
9278
  /***/ }),
9279
9279
 
@@ -9285,7 +9285,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9285
9285
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9286
9286
 
9287
9287
  "use strict";
9288
- 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\n\nvar syncNativeHls = function syncNativeHls() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _videoElement = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var startSyncLoop = function 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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n realPosition = _calculateSyncDiffere.realPosition,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos, ping) {\n var seekRanges = _videoElement.buffered;\n var seekRange = {};\n\n for (var i = 0; i < seekRanges.length; i++) {\n var _c_start = seekRanges.start(i);\n\n var _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 var position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position: position,\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,\n realPosition: position,\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,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPosition: position,\n isBufferSufficient: false\n };\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve, reject) {\n if (_videoElement.currentTime !== time) {\n var diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var sgtid = null;\n\n var stalledGenerator = function stalledGenerator() {\n clearTimeout(sgtid);\n sgtid = setTimeout(function () {\n if (_videoElement.paused === false) {\n handleStalledWaiting();\n }\n }, 1000);\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n videoElement = _ref2.videoElement,\n _ref2$syncOnLevelSwit = _ref2.syncOnLevelSwitch,\n syncOnLevelSwitch = _ref2$syncOnLevelSwit === void 0 ? false : _ref2$syncOnLevelSwit,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _videoElement = videoElement;\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === 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 (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _videoElement.addEventListener('timeupdate', stalledGenerator);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function 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\n if (_videoElement) {\n _videoElement.removeEventListener('timeupdate', stalledGenerator);\n\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncNativeHls);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-native-hls.js?");
9288
+ 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\n\nvar syncNativeHls = function syncNativeHls() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _videoElement = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var startSyncLoop = function 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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n realPosition = _calculateSyncDiffere.realPosition,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos, ping) {\n var seekRanges = _videoElement.buffered;\n var seekRange = {};\n\n for (var i = 0; i < seekRanges.length; i++) {\n var _c_start = seekRanges.start(i);\n\n var _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 var position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position: position,\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,\n realPosition: position,\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,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPosition: position,\n isBufferSufficient: false\n };\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve, reject) {\n if (_videoElement.currentTime !== time) {\n var diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var sgtid = null;\n\n var stalledGenerator = function stalledGenerator() {\n clearTimeout(sgtid);\n sgtid = setTimeout(function () {\n if (_videoElement.paused === false) {\n handleStalledWaiting();\n }\n }, 1000);\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n videoElement = _ref2.videoElement,\n _ref2$syncOnLevelSwit = _ref2.syncOnLevelSwitch,\n syncOnLevelSwitch = _ref2$syncOnLevelSwit === void 0 ? false : _ref2$syncOnLevelSwit,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _videoElement = videoElement;\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === 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 (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _videoElement.addEventListener('timeupdate', stalledGenerator);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function 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\n if (_videoElement) {\n _videoElement.removeEventListener('timeupdate', stalledGenerator);\n\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncNativeHls);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-native-hls.js?");
9289
9289
 
9290
9290
  /***/ }),
9291
9291
 
@@ -9297,7 +9297,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9297
9297
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9298
9298
 
9299
9299
  "use strict";
9300
- 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\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\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\n\nvar syncVodShakaDash = function syncVodShakaDash() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var _roomId = null;\n var _syncDisabled = false;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var seekingDebounceId = null;\n var seekingDebounceTimeout = 300;\n var isPlaying = false;\n var isProgrammaticallySeeked = false;\n var isForcedMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (_syncDisabled) {\n room._log('--- Sync loop will not start due to sync force disabled ---');\n\n return;\n }\n\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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (syncData.masterFragmentSn) {\n playMedia();\n } else {\n pauseMedia();\n }\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(position + (isPlaying ? seekDuration : 0) - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement) {\n //TODO: shit fix ... data channel with other participant is not opened yet so we wait\n setTimeout(function () {\n restartSyncLoop();\n }, 1000);\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var handleRemoveRemoteParticipant = function handleRemoveRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var buffering = function buffering(event) {\n if (event.buffering) {\n handleStalledWaiting();\n }\n };\n\n var executePlayerIotEvents = function executePlayerIotEvents(data) {\n var rid = _roomId || room.roomId;\n\n if (data.attributeName === 'playerReplay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n seekTo(0).then(function () {\n return playMedia();\n });\n }\n\n if (data.attributeName === 'playerPlay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n playMedia();\n }\n\n if (data.attributeName === 'playerPause' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n pauseMedia();\n }\n };\n\n var parseIotEvents = function parseIotEvents(data) {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(function (event) {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents(_objectSpread(_objectSpread({}, event), {}, {\n roomId: data.roomId,\n userId: data.userId\n }));\n }\n });\n }\n\n if (data.operation === 'sendMessage') {\n executePlayerIotEvents(data);\n }\n }\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n } else if (msg.videoroom === 'message') {\n // ignoring non studio commands if master\n if (isForcedMaster && msg.from !== null) {\n return;\n }\n\n if (_syncDisabled) {\n return;\n }\n\n if (msg.user_action === 'sync_seeking') {\n seekMedia(msg).catch(function () {});\n } else if (msg.user_action === 'sync_seeked') {} else if (msg.user_action === 'sync_play' || msg.action === 'sync_play') {\n playMedia();\n } else if (msg.user_action === 'sync_pause' || msg.action === 'sync_pause') {\n pauseMedia();\n }\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn) {\n var fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n var seekMedia = function seekMedia(msg) {\n msg = _objectSpread({\n userId: msg.from\n }, msg.text && JSON.parse(msg.text));\n\n if (msg.handleId !== room.handleId) {\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0),\n position = _calculateSyncDiffere2.position,\n isBufferSufficient = _calculateSyncDiffere2.isBufferSufficient; //TODO: right ping\n\n\n if (position) {\n return seekTo(position).then(function () {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n var prePlay = function prePlay() {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n var wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(function () {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(function () {\n return true;\n }).finally(function () {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n var playMedia = function playMedia() {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(function () {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n var pauseMedia = function pauseMedia() {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', function () {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve) {\n if (_videoElement.currentTime !== time) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('seeked', function () {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(function () {});\n }\n };\n\n var handleSeeking = function handleSeeking() {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(function () {\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n roomSession.sendSystemMessage('sync_seeking', {\n timestamp: new Date().getTime(),\n handleId: room.handleId,\n fragment: \"0\",\n //isPlaying ? \"1\":\"0\",\n fragment_pos: Number(fragmentPosition)\n }, undefined, null).catch(function () {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n var handleSeeked = function handleSeeked() {};\n\n var handleEnded = function handleEnded() {};\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n shakaInstance = _ref2.shakaInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster,\n _ref2$isStudio = _ref2.isStudio,\n isStudio = _ref2$isStudio === void 0 ? false : _ref2$isStudio,\n roomId = _ref2.roomId,\n syncDisabled = _ref2.syncDisabled;\n\n _libraryInstance = shakaInstance || libraryInstance;\n _videoElement = _libraryInstance.getMediaElement();\n _roomId = roomId;\n _syncDisabled = syncDisabled;\n\n if (!_libraryInstance) {\n console.log('No shaka player instance');\n return;\n }\n\n emitter.emit('playerSyncing', false);\n isForcedMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.on('data', parseDataEvents);\n wt.iot.$on('message', parseIotEvents);\n\n if (isForcedMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_libraryInstance && _videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(function () {\n _libraryInstance.addEventListener('buffering', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n\n _videoElement.addEventListener('seeking', handleSeeking);\n\n _videoElement.addEventListener('seeked', handleSeeked);\n\n _videoElement.addEventListener('ended', handleEnded);\n\n startSyncLoop();\n });\n }\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_libraryInstance) {\n _libraryInstance.removeEventListener('buffering', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _libraryInstance = null;\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodShakaDash);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-shaka-dash-vod.js?");
9300
+ 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\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\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\n\nvar syncVodShakaDash = function syncVodShakaDash() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var _roomId = null;\n var _syncDisabled = false;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var seekingDebounceId = null;\n var seekingDebounceTimeout = 300;\n var isPlaying = false;\n var isProgrammaticallySeeked = false;\n var isForcedMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (_syncDisabled) {\n room._log('--- Sync loop will not start due to sync force disabled ---');\n\n return;\n }\n\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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (syncData.masterFragmentSn) {\n playMedia();\n } else {\n pauseMedia();\n }\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(position + (isPlaying ? seekDuration : 0) - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement) {\n //TODO: shit fix ... data channel with other participant is not opened yet so we wait\n setTimeout(function () {\n restartSyncLoop();\n }, 1000);\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var handleRemoveRemoteParticipant = function handleRemoveRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var buffering = function buffering(event) {\n if (event.buffering) {\n handleStalledWaiting();\n }\n };\n\n var executePlayerIotEvents = function executePlayerIotEvents(data) {\n var rid = _roomId || room.roomId;\n\n if (data.attributeName === 'playerReplay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n seekTo(0).then(function () {\n return playMedia();\n });\n }\n\n if (data.attributeName === 'playerPlay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n playMedia();\n }\n\n if (data.attributeName === 'playerPause' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n pauseMedia();\n }\n };\n\n var parseIotEvents = function parseIotEvents(data) {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(function (event) {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents(_objectSpread(_objectSpread({}, event), {}, {\n roomId: data.roomId,\n userId: data.userId\n }));\n }\n });\n }\n\n if (data.operation === 'sendMessage') {\n executePlayerIotEvents(data);\n }\n }\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n } else if (msg.videoroom === 'message') {\n // ignoring non studio commands if master\n if (isForcedMaster && msg.from !== null) {\n return;\n }\n\n if (_syncDisabled) {\n return;\n }\n\n if (msg.user_action === 'sync_seeking') {\n seekMedia(msg).catch(function () {});\n } else if (msg.user_action === 'sync_seeked') {} else if (msg.user_action === 'sync_play' || msg.action === 'sync_play') {\n playMedia();\n } else if (msg.user_action === 'sync_pause' || msg.action === 'sync_pause') {\n pauseMedia();\n }\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn) {\n var fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n var seekMedia = function seekMedia(msg) {\n msg = _objectSpread({\n userId: msg.from\n }, msg.text && JSON.parse(msg.text));\n\n if (msg.handleId !== room.handleId) {\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0),\n position = _calculateSyncDiffere2.position,\n isBufferSufficient = _calculateSyncDiffere2.isBufferSufficient; //TODO: right ping\n\n\n if (position) {\n return seekTo(position).then(function () {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n var prePlay = function prePlay() {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n var wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(function () {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(function () {\n return true;\n }).finally(function () {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n var playMedia = function playMedia() {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(function () {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n var pauseMedia = function pauseMedia() {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', function () {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve) {\n if (_videoElement.currentTime !== time) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('seeked', function () {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(function () {});\n }\n };\n\n var handleSeeking = function handleSeeking() {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(function () {\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n roomSession.sendSystemMessage('sync_seeking', {\n timestamp: new Date().getTime(),\n handleId: room.handleId,\n fragment: \"0\",\n //isPlaying ? \"1\":\"0\",\n fragment_pos: Number(fragmentPosition)\n }, undefined, null).catch(function () {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n var handleSeeked = function handleSeeked() {};\n\n var handleEnded = function handleEnded() {};\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n shakaInstance = _ref2.shakaInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster,\n _ref2$isStudio = _ref2.isStudio,\n isStudio = _ref2$isStudio === void 0 ? false : _ref2$isStudio,\n roomId = _ref2.roomId,\n syncDisabled = _ref2.syncDisabled;\n\n _libraryInstance = shakaInstance || libraryInstance;\n _videoElement = _libraryInstance.getMediaElement();\n _roomId = roomId;\n _syncDisabled = syncDisabled;\n\n if (!_libraryInstance) {\n console.log('No shaka player instance');\n return;\n }\n\n emitter.emit('playerSyncing', false);\n isForcedMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.on('data', parseDataEvents);\n wt.iot.$on('message', parseIotEvents);\n\n if (isForcedMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_libraryInstance && _videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(function () {\n _libraryInstance.addEventListener('buffering', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n\n _videoElement.addEventListener('seeking', handleSeeking);\n\n _videoElement.addEventListener('seeked', handleSeeked);\n\n _videoElement.addEventListener('ended', handleEnded);\n\n startSyncLoop();\n });\n }\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_libraryInstance) {\n _libraryInstance.removeEventListener('buffering', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _libraryInstance = null;\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodShakaDash);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-shaka-dash-vod.js?");
9301
9301
 
9302
9302
  /***/ }),
9303
9303
 
@@ -9309,7 +9309,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9309
9309
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9310
9310
 
9311
9311
  "use strict";
9312
- 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\n\nvar syncDaznDash = function syncDaznDash() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var buffering = function buffering(event) {\n if (event.buffering) {\n handleStalledWaiting();\n }\n };\n\n var startSyncLoop = function 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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n realPosition = _calculateSyncDiffere.realPosition,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos, ping) {\n var seekRanges = _videoElement.buffered;\n var seekRange = {};\n\n for (var i = 0; i < seekRanges.length; i++) {\n var _c_start = seekRanges.start(i);\n\n var _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 var position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position: position,\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,\n realPosition: position,\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,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPosition: position,\n isBufferSufficient: false\n };\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve, reject) {\n if (_videoElement.currentTime !== time) {\n var diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n }; // const seekTo = (time) => {\n // return new Promise((resolve, reject) => {\n // if(_videoElement.currentTime !== time) {\n // let __ = Date.now();\n // isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n // _videoElement.addEventListener('playing', () => {\n // room._log(`It took the player ${(Date.now() - __) / 1000} seconds to seek `);\n // isProgrammaticallySeeked = false;\n // resolve();\n // }, {once:true});\n // _videoElement.currentTime = time;\n // } else resolve()\n // });\n // };\n\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n libraryInstance = _ref2.libraryInstance,\n shakaInstance = _ref2.shakaInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _libraryInstance = libraryInstance || shakaInstance;\n _videoElement = _libraryInstance.getMediaElement();\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === 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 (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _libraryInstance.addEventListener('buffering', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function 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\n if (_libraryInstance) {\n _libraryInstance.removeEventListener('buffering', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDaznDash);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-shaka-dash.js?");
9312
+ 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\n\nvar syncDaznDash = function syncDaznDash() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var buffering = function buffering(event) {\n if (event.buffering) {\n handleStalledWaiting();\n }\n };\n\n var startSyncLoop = function 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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n realPosition = _calculateSyncDiffere.realPosition,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos, ping) {\n var seekRanges = _videoElement.buffered;\n var seekRange = {};\n\n for (var i = 0; i < seekRanges.length; i++) {\n var _c_start = seekRanges.start(i);\n\n var _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 var position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position: position,\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,\n realPosition: position,\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,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPosition: position,\n isBufferSufficient: false\n };\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve, reject) {\n if (_videoElement.currentTime !== time) {\n var diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n }; // const seekTo = (time) => {\n // return new Promise((resolve, reject) => {\n // if(_videoElement.currentTime !== time) {\n // let __ = Date.now();\n // isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n // _videoElement.addEventListener('playing', () => {\n // room._log(`It took the player ${(Date.now() - __) / 1000} seconds to seek `);\n // isProgrammaticallySeeked = false;\n // resolve();\n // }, {once:true});\n // _videoElement.currentTime = time;\n // } else resolve()\n // });\n // };\n\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n libraryInstance = _ref2.libraryInstance,\n shakaInstance = _ref2.shakaInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _libraryInstance = libraryInstance || shakaInstance;\n _videoElement = _libraryInstance.getMediaElement();\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === 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 (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _libraryInstance.addEventListener('buffering', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function 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\n if (_libraryInstance) {\n _libraryInstance.removeEventListener('buffering', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDaznDash);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-shaka-dash.js?");
9313
9313
 
9314
9314
  /***/ }),
9315
9315
 
@@ -9321,7 +9321,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9321
9321
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9322
9322
 
9323
9323
  "use strict";
9324
- 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\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\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\n\n\nvar syncUniversal = function syncUniversal() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _emitter = Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])();\n\n var _playerInterface = null;\n var _playerInterfaceOptions = {\n isLive: true,\n ignoreBufferedTimeRanges: true,\n useSeekBy: false,\n syncBySegments: false,\n disableFastSeek: false\n };\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var waitForPlayingEventAfterSeek = 5000;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var startSyncLoop = function 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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_playerInterface.isPaused) _playerInterface.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n realPosition = _calculateSyncDiffere.realPosition,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(realPosition, seekDuration, getCurrentSegmentPosition());\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration, \" seconds\"));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_playerInterface.isPaused === false) {\n _emitter.once('timeupdate', restartSyncLoop);\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _playerInterface.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos, ping) {\n var seekRanges = _playerInterface.buffered;\n var position = (fragmentPos + ping / 2) / 1000;\n\n if (seekRanges && !_playerInterfaceOptions.ignoreBufferedTimeRanges) {\n var seekRange = {};\n\n for (var i = 0; i < seekRanges.length; i++) {\n var _c_start = seekRanges.start(i);\n\n var _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,\n realPosition: position,\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,\n realPosition: position,\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,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n isBufferSufficient: false\n };\n } else {\n return {\n position: position,\n realPosition: position,\n isBufferSufficient: true\n };\n }\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve, reject) {\n if (_playerInterface.currentTime !== time) {\n var diff = time - _playerInterface.currentTime;\n\n if (_playerInterface.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var _handleFailed = function _handleFailed() {\n if (wasPaused) {\n _playerInterface.pause();\n }\n\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n var _fastForward = function _fastForward() {\n isProgrammaticallySeeked = true;\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n _emitter.off('stalled', _handleFailed);\n\n if (wasPaused && !_playerInterfaceOptions.isLive) {\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(function () {\n _fastForward();\n }).catch(_handleFailed);\n } else {\n _fastForward();\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var currentTimestamp = Date.now();\n var __failsafeId = null;\n\n var _resolve = function _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 var handlePlaying = function 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 var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_playerInterface.isPaused;\n };\n\n var handleBuffering = function handleBuffering() {\n room._log('handleBuffering');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _playerInterface.isPaused;\n }\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 getHandlers: function getHandlers() {\n return {\n handlePause: function handlePause(event) {\n room._log('handlePause');\n\n _emitter.emit('pause', event);\n },\n handlePlaying: function handlePlaying(event) {\n room._log('handlePlaying');\n\n _emitter.emit('playing', event);\n },\n handleBuffering: function handleBuffering(event) {\n room._log('handleBuffering');\n\n _emitter.emit('buffering', event);\n },\n handleStalled: function handleStalled(event) {\n room._log('handleBuffering');\n\n room._log('handleStalled');\n\n _emitter.emit('buffering', event);\n\n _emitter.emit('stalled', event);\n },\n handleTimeupdate: function handleTimeupdate(event) {\n room._log('handleTimeupdate');\n\n _emitter.emit('timeupdate', event);\n }\n };\n },\n initialize: function initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n playerInterface = _ref2.playerInterface;\n\n _playerInterface = playerInterface;\n _playerInterfaceOptions = _objectSpread(_objectSpread({}, _playerInterfaceOptions), _playerInterface.options || {});\n\n room._log('Interface options passed: ', _playerInterface.options || {});\n\n room._log('All interface options: ', _playerInterfaceOptions);\n\n shouldPropagateMaster = false;\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 (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\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: function destroy() {\n var _playerInterface2;\n\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\n if (typeof ((_playerInterface2 = _playerInterface) === null || _playerInterface2 === void 0 ? void 0 : _playerInterface2.destroy) === 'function') {\n var _playerInterface3;\n\n (_playerInterface3 = _playerInterface) === null || _playerInterface3 === void 0 ? void 0 : _playerInterface3.destroy();\n }\n\n _playerInterface = null;\n\n _emitter.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncUniversal);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-universal.js?");
9324
+ 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\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\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\n\n\nvar syncUniversal = function syncUniversal() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _emitter = Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])();\n\n var _playerInterface = null;\n var _playerInterfaceOptions = {\n isLive: true,\n ignoreBufferedTimeRanges: true,\n useSeekBy: false,\n syncBySegments: false,\n disableFastSeek: false\n };\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var waitForPlayingEventAfterSeek = 5000;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var startSyncLoop = function 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 var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\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 };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var 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 var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_playerInterface.isPaused) _playerInterface.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n realPosition = _calculateSyncDiffere.realPosition,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= 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) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(realPosition, seekDuration, getCurrentSegmentPosition());\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration, \" seconds\"));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_playerInterface.isPaused === false) {\n _emitter.once('timeupdate', restartSyncLoop);\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _playerInterface.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos, ping) {\n var seekRanges = _playerInterface.buffered;\n var position = (fragmentPos + ping / 2) / 1000;\n\n if (seekRanges && !_playerInterfaceOptions.ignoreBufferedTimeRanges) {\n var seekRange = {};\n\n for (var i = 0; i < seekRanges.length; i++) {\n var _c_start = seekRanges.start(i);\n\n var _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,\n realPosition: position,\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,\n realPosition: position,\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,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n isBufferSufficient: false\n };\n } else {\n return {\n position: position,\n realPosition: position,\n isBufferSufficient: true\n };\n }\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve, reject) {\n if (_playerInterface.currentTime !== time) {\n var diff = time - _playerInterface.currentTime;\n\n if (_playerInterface.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var _handleFailed = function _handleFailed() {\n if (wasPaused) {\n _playerInterface.pause();\n }\n\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n var _fastForward = function _fastForward() {\n isProgrammaticallySeeked = true;\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n _emitter.off('stalled', _handleFailed);\n\n if (wasPaused && !_playerInterfaceOptions.isLive) {\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(function () {\n _fastForward();\n }).catch(_handleFailed);\n } else {\n _fastForward();\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var currentTimestamp = Date.now();\n var __failsafeId = null;\n\n var _resolve = function _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 var handlePlaying = function 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 var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_playerInterface.isPaused;\n };\n\n var handleBuffering = function handleBuffering() {\n room._log('handleBuffering');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _playerInterface.isPaused;\n }\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\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 fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function 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: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function 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 var propagateMasterFunc = function 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 getHandlers: function getHandlers() {\n return {\n handlePause: function handlePause(event) {\n room._log('handlePause');\n\n _emitter.emit('pause', event);\n },\n handlePlaying: function handlePlaying(event) {\n room._log('handlePlaying');\n\n _emitter.emit('playing', event);\n },\n handleBuffering: function handleBuffering(event) {\n room._log('handleBuffering');\n\n _emitter.emit('buffering', event);\n },\n handleStalled: function handleStalled(event) {\n room._log('handleBuffering');\n\n room._log('handleStalled');\n\n _emitter.emit('buffering', event);\n\n _emitter.emit('stalled', event);\n },\n handleTimeupdate: function handleTimeupdate(event) {\n room._log('handleTimeupdate');\n\n _emitter.emit('timeupdate', event);\n }\n };\n },\n initialize: function initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n playerInterface = _ref2.playerInterface;\n\n _playerInterface = playerInterface;\n _playerInterfaceOptions = _objectSpread(_objectSpread({}, _playerInterfaceOptions), _playerInterface.options || {});\n\n room._log('Interface options passed: ', _playerInterface.options || {});\n\n room._log('All interface options: ', _playerInterfaceOptions);\n\n shouldPropagateMaster = false;\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 (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\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: function destroy() {\n var _playerInterface2;\n\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\n if (typeof ((_playerInterface2 = _playerInterface) === null || _playerInterface2 === void 0 ? void 0 : _playerInterface2.destroy) === 'function') {\n var _playerInterface3;\n\n (_playerInterface3 = _playerInterface) === null || _playerInterface3 === void 0 ? void 0 : _playerInterface3.destroy();\n }\n\n _playerInterface = null;\n\n _emitter.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncUniversal);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-universal.js?");
9325
9325
 
9326
9326
  /***/ }),
9327
9327
 
@@ -9381,7 +9381,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var aws_
9381
9381
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9382
9382
 
9383
9383
  "use strict";
9384
- 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 _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\nfunction _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\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\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\n// Watch together janus webrtc library\n\n\n\n\nvar Room = /*#__PURE__*/function () {\n function Room(debug) {\n var _this = this;\n\n _classCallCheck(this, Room);\n\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(function (safariVp8) {\n _this.safariVp8 = safariVp8;\n }); // Let's get it started\n\n this.whenInitialized = this.initialize();\n }\n\n _createClass(Room, [{\n key: \"initialize\",\n value: function initialize() {\n var _this2 = this;\n\n return this.safariVp8TestPromise.then(function () {\n return _this2;\n });\n }\n }, {\n key: \"createSession\",\n value: function createSession() {\n var constructId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'reactooroom';\n var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n return new RoomSession(constructId, type, _objectSpread({\n debug: this.debug\n }, options));\n }\n }], [{\n key: \"testSafariVp8\",\n value: function testSafariVp8() {\n return new Promise(function (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 var 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 key: \"isWebrtcSupported\",\n value: function 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 return Room;\n}();\n\nvar RoomSession = /*#__PURE__*/function () {\n function RoomSession() {\n var constructId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'reactooroom';\n var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n _classCallCheck(this, RoomSession);\n\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; //TODO: remove this\n\n this.isMonitor = false; // currently used just for classroom context so monitor user only subscribes to participants and not trainer (for other monitor this flag is not necessary)\n\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; //TODO: do it better\n // double click prevention\n\n this.connectingPromise = null;\n this.disconnectingPromise = null;\n this._ipv6Support = false;\n this._retries = 0;\n this._maxRetries = 3;\n this._keepAliveId = null;\n this._participants = [];\n this._observerIds = [];\n this._talkbackIds = [];\n this._instuctorId = null;\n this._hasJoined = false;\n this._isStreaming = false;\n this._isPublished = false;\n this._isDataChannelOpen = false;\n this._dataChannelTimeoutId = null;\n this._messageTimeoutId = 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 = _objectSpread(_objectSpread({}, RoomSession.subscriptionRules), this.options.subscriptionRules || {});\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 _createClass(RoomSession, [{\n key: \"_participantShouldSubscribe\",\n value: function _participantShouldSubscribe(userId) {\n var allowedObservers = this._observerIds || [];\n var allowedTalkback = this._talkbackIds || [];\n var allowedInstructor = this._instuctorId || null;\n var localUserRole = 'participant';\n\n if (this.isMonitor) {\n localUserRole = 'monitor';\n } else if (allowedObservers.indexOf(this.userId) > -1) {\n localUserRole = 'observer';\n } else if (allowedTalkback.indexOf(this.userId) > -1) {\n localUserRole = 'talkback';\n } else if (this.userId === allowedInstructor) {\n localUserRole = 'instructor';\n }\n\n var remoteUserRole = 'participant';\n\n if (allowedObservers.indexOf(userId) > -1) {\n remoteUserRole = 'observer';\n } else if (allowedTalkback.indexOf(userId) > -1) {\n remoteUserRole = 'talkback';\n } else if (userId === allowedInstructor) {\n remoteUserRole = 'instructor';\n }\n\n var mode = allowedInstructor !== null ? 'videoWall' : 'watchTogether';\n return this.subscriptionRules[localUserRole][mode].indexOf(remoteUserRole) > -1;\n }\n }, {\n key: \"_getAddParticipantEventName\",\n value: function _getAddParticipantEventName(handleId) {\n var 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 var allowedTalkback = this._talkbackIds || [];\n var allowedObservers = this._observerIds || [];\n var allowedInstructor = this._instuctorId || null;\n var eventName = 'addRemoteParticipant';\n\n if (handle.userId === allowedInstructor) {\n eventName = 'addRemoteInstructor';\n }\n\n if (allowedTalkback.indexOf(handle.userId) > -1) {\n eventName = 'addRemoteTalkback';\n }\n\n if (allowedObservers.indexOf(handle.userId) > -1) {\n eventName = 'addRemoteObserver';\n }\n\n return eventName;\n }\n }, {\n key: \"_getRemoveParticipantEventName\",\n value: function _getRemoveParticipantEventName(handleId) {\n var 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 var allowedTalkback = this._talkbackIds || [];\n var allowedObservers = this._observerIds || [];\n var allowedInstructor = this._instuctorId || null;\n var eventName = 'removeRemoteParticipant';\n\n if (handle.userId === allowedInstructor) {\n eventName = 'removeRemoteInstructor';\n }\n\n if (allowedTalkback.indexOf(handle.userId) > -1) {\n eventName = 'removeRemoteTalkback';\n }\n\n if (allowedObservers.indexOf(handle.userId) > -1) {\n eventName = 'removeRemoteObserver';\n }\n\n return eventName;\n }\n }, {\n key: \"sendMessage\",\n value: function sendMessage(handleId) {\n var message = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n body: 'Example Body'\n };\n var dontWait = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n var dontResolveOnAck = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n return this._send(_objectSpread({\n \"janus\": \"message\",\n \"handle_id\": handleId\n }, message), dontWait, dontResolveOnAck).then(function (json) {\n if (json && json[\"janus\"] === \"success\") {\n var plugindata = json[\"plugindata\"] || {};\n var data = plugindata[\"data\"];\n return Promise.resolve(data);\n }\n\n return Promise.resolve();\n }).catch(function (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 key: \"_send\",\n value: function _send() {\n var _this3 = this;\n\n var request = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var ignoreResponse = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n var dontResolveOnAck = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n var transaction = RoomSession.randomString(12);\n\n var requestData = _objectSpread(_objectSpread({}, request), {}, {\n transaction: transaction,\n token: this.token\n }, this.sessionId && {\n 'session_id': this.sessionId\n } || {});\n\n return new Promise(function (resolve, reject) {\n var parseResponse = function parseResponse(event) {\n var json = JSON.parse(event.data);\n var r_transaction = json['transaction'];\n\n if (r_transaction === transaction && (!dontResolveOnAck || json['janus'] !== 'ack')) {\n clearTimeout(_this3._messageTimeoutId);\n\n _this3.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 _this3.disconnect(true);\n }\n\n reject({\n type: 'error',\n id: 2,\n message: 'send failed',\n data: json,\n requestData: requestData\n });\n } else {\n resolve(json);\n }\n }\n };\n\n if (ignoreResponse) {\n if (_this3.ws && _this3.ws.readyState === 1) {\n _this3.ws.send(JSON.stringify(requestData));\n }\n\n resolve();\n } else {\n if (_this3.ws && _this3.ws.readyState === 1) {\n _this3.ws.addEventListener('message', parseResponse);\n\n _this3._messageTimeoutId = setTimeout(function () {\n _this3.ws.removeEventListener('message', parseResponse);\n\n reject({\n type: 'error',\n id: 3,\n message: 'send timeout',\n data: requestData\n });\n }, 10000);\n\n _this3.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 key: \"_connectionClosed\",\n value: function _connectionClosed() {\n var _this4 = this;\n\n if (this.disconnectingPromise || this.connectingPromise) {\n return;\n }\n\n if (this._retries < this._maxRetries) {\n setTimeout(function () {\n _this4._retries++;\n\n _this4._reconnect().catch(function (e) {\n _this4.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 key: \"_wipeListeners\",\n value: function _wipeListeners() {\n if (this.ws) {\n this.ws.removeEventListener('close', this.__connectionClosedBoundFn);\n this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);\n }\n }\n }, {\n key: \"_startKeepAlive\",\n value: function _startKeepAlive() {\n var _this5 = this;\n\n this._send({\n \"janus\": \"keepalive\"\n }).then(function (json) {\n if (json[\"janus\"] !== 'ack') {\n _this5.emit('error', {\n type: 'warning',\n id: 5,\n message: 'keepalive response suspicious',\n data: json[\"janus\"]\n });\n }\n }).catch(function (e) {\n _this5.emit('error', {\n type: 'warning',\n id: 6,\n message: 'keepalive dead',\n data: e\n });\n\n _this5._connectionClosed();\n });\n\n this._keepAliveId = setTimeout(function () {\n _this5._startKeepAlive();\n }, 30000);\n }\n }, {\n key: \"_stopKeepAlive\",\n value: function _stopKeepAlive() {\n clearTimeout(this._keepAliveId);\n }\n }, {\n key: \"_handleWsEvents\",\n value: function _handleWsEvents(event) {\n var _this6 = this;\n\n var json = JSON.parse(event.data);\n var sender = json[\"sender\"];\n var type = json[\"janus\"];\n\n var handle = this._getHandle(sender);\n\n if (!handle) {\n return;\n }\n\n if (type === \"trickle\") {\n var candidate = json[\"candidate\"];\n var 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 var result = msg[\"result\"] || null;\n\n var _event = msg[\"videoroom\"] || null;\n\n var list = msg[\"publishers\"] || {};\n var leaving = msg[\"leaving\"]; //let joining = msg[\"joining\"];\n\n var unpublished = msg[\"unpublished\"];\n var error = msg[\"error\"];\n\n if (_event === \"joined\") {\n this.id = msg[\"id\"];\n this.privateId = msg[\"private_id\"];\n this._hasJoined = true;\n this.emit('joined', true);\n\n this._log('We have successfully joined Room');\n\n var _loop = function _loop(f) {\n var userId = list[f][\"display\"];\n var streams = list[f][\"streams\"] || [];\n var id = list[f][\"id\"];\n\n for (var i in streams) {\n streams[i][\"id\"] = id;\n streams[i][\"display\"] = userId;\n }\n\n _this6._log('Remote userId: ', userId);\n\n if (_this6._participantShouldSubscribe(userId)) {\n _this6._log('Creating user: ', userId);\n\n _this6._createParticipant(userId, id).then(function (handle) {\n return _this6.sendMessage(handle.handleId, {\n body: {\n \"request\": \"join\",\n \"room\": _this6.roomId,\n \"ptype\": \"subscriber\",\n \"feed\": id,\n \"private_id\": _this6.privateId,\n pin: _this6.pin\n }\n });\n }).catch(function (err) {\n _this6.emit('error', err);\n });\n }\n };\n\n for (var f in list) {\n _loop(f);\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 var _loop2 = function _loop2(_f) {\n var userId = list[_f][\"display\"];\n var streams = list[_f][\"streams\"] || [];\n var id = list[_f][\"id\"];\n\n for (var i in streams) {\n streams[i][\"id\"] = id;\n streams[i][\"display\"] = userId;\n }\n\n _this6._log('Remote userId: ', userId);\n\n if (_this6._participantShouldSubscribe(userId)) {\n _this6._log('Creating user: ', userId);\n\n _this6._createParticipant(userId, id).then(function (handle) {\n return _this6.sendMessage(handle.handleId, {\n body: {\n \"request\": \"join\",\n \"room\": _this6.roomId,\n \"ptype\": \"subscriber\",\n \"feed\": id,\n \"private_id\": _this6.privateId,\n pin: _this6.pin\n }\n });\n }).catch(function (err) {\n _this6.emit('error', err);\n });\n }\n };\n\n for (var _f in list) {\n _loop2(_f);\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(function () {});\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(function (err) {\n _this6.emit('error', err);\n });\n } else if (this.sessiontype === 'streaming') {\n this._publishRemote(this.handleId, jsep).catch(function (err) {\n _this6.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(function () {\n return null;\n });\n }\n }\n } //REMOTE\n else {\n var _plugindata = json[\"plugindata\"] || {};\n\n var _msg = _plugindata[\"data\"] || {};\n\n var _jsep2 = json[\"jsep\"];\n var _event2 = _msg[\"videoroom\"];\n var _error = _msg[\"error\"];\n\n if (_event2 === \"attached\") {\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: handle.userId,\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 (_jsep2) {\n this._publishRemote(handle.handleId, _jsep2).catch(function (err) {\n _this6.emit('error', err);\n });\n }\n }\n }\n }, {\n key: \"_handleDataEvents\",\n value: function _handleDataEvents(handleId, type, data) {\n var 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 var 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 var _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 var 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 key: \"_removeParticipant\",\n value: function _removeParticipant(handleId, rfid) {\n var _this7 = this;\n\n var removeHandle = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n\n var 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(function () {\n return removeHandle ? _this7._send({\n \"janus\": \"detach\",\n \"handle_id\": handleId\n }, true) : Promise.resolve();\n }).finally(function () {\n try {\n if (handle.webrtcStuff.stream && !_this7.isRestarting) {\n handle.webrtcStuff.stream.getTracks().forEach(function (track) {\n return track.stop();\n });\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(function (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 === _this7.handleId) {\n _this7._isDataChannelOpen = false;\n _this7._isPublished = false;\n\n _this7.emit('published', {\n status: false,\n hasStream: false\n });\n\n _this7.emit('removeLocalParticipant', {\n id: handleId,\n userId: handle.userId\n });\n } else {\n _this7.emit(_this7._getRemoveParticipantEventName(handleId), {\n id: handleId,\n userId: handle.userId\n });\n }\n\n if (removeHandle) {\n var handleIndex = _this7._participants.findIndex(function (p) {\n return p.handleId === handleId;\n });\n\n _this7._participants.splice(handleIndex, 1);\n }\n\n return true;\n });\n }\n }, {\n key: \"_createParticipant\",\n value: function _createParticipant() {\n var _this8 = this;\n\n var userId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n var rfid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n return this._send({\n \"janus\": \"attach\",\n \"plugin\": this.pluginName\n }).then(function (json) {\n var handleId = json.data[\"id\"];\n var handle = {\n handleId: handleId,\n rfid: rfid,\n userId: 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 _this8._participants.push(handle);\n\n return handle;\n });\n }\n }, {\n key: \"_joinRoom\",\n value: function _joinRoom(roomId, pin, userId) {\n return this.sendMessage(this.handleId, {\n body: {\n \"request\": \"join\",\n \"room\": roomId,\n \"pin\": pin,\n \"ptype\": \"publisher\",\n \"display\": userId\n }\n }, false, true);\n }\n }, {\n key: \"_watchStream\",\n value: function _watchStream(id) {\n return this.sendMessage(this.handleId, {\n body: {\n \"request\": \"watch\",\n id: parseInt(id)\n }\n }, false, true);\n }\n }, {\n key: \"_leaveRoom\",\n value: function _leaveRoom() {\n var _this9 = this;\n\n var dontWait = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n return this._hasJoined ? this.sendMessage(this.handleId, {\n body: {\n \"request\": \"leave\"\n }\n }, dontWait).finally(function () {\n _this9._hasJoined = false;\n\n _this9.emit('joined', false);\n }) : Promise.resolve();\n } // internal reconnect\n\n }, {\n key: \"_reconnect\",\n value: function _reconnect() {\n var _this10 = this;\n\n if (this.connectingPromise) {\n return this.connectingPromise;\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.connectingPromise = new Promise(function (resolve, reject) {\n _this10.emit('joining', true);\n\n _this10.ws = new WebSocket(_this10.server, 'janus-protocol');\n _this10.__connectionClosedBoundFn = _this10._connectionClosed.bind(_this10);\n _this10.__handleWsEventsBoundFn = _this10._handleWsEvents.bind(_this10);\n\n _this10.ws.addEventListener('close', _this10.__connectionClosedBoundFn);\n\n _this10.ws.addEventListener('message', _this10.__handleWsEventsBoundFn);\n\n _this10.ws.onopen = function () {\n _this10._send({\n \"janus\": \"claim\"\n }).then(function (json) {\n _this10.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n _this10._startKeepAlive();\n\n _this10.connectingPromise = null;\n\n _this10.emit('joining', false);\n\n _this10._retries = 0;\n resolve(json);\n }).catch(function (error) {\n _this10.connectingPromise = null;\n\n _this10.emit('joining', false);\n\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 _this10.ws.onerror = function (e) {\n _this10.connectingPromise = null;\n\n _this10.emit('joining', false);\n\n reject({\n type: 'warning',\n id: 12,\n message: 'ws reconnection error',\n data: e\n });\n };\n });\n return this.connectingPromise;\n }\n }, {\n key: \"connect\",\n value: function connect(roomId, pin, server, iceServers, token, userId) {\n var _this11 = this;\n\n var webrtcVersion = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 0;\n var initialBitrate = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 0;\n var isMonitor = arguments.length > 8 ? arguments[8] : undefined;\n var recordingFilename = arguments.length > 9 ? arguments[9] : undefined;\n\n if (this.connectingPromise) {\n return this.connectingPromise;\n }\n\n this.emit('joined', false);\n\n if (this.ws) {\n this._wipeListeners();\n }\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = null;\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.userId = userId;\n this.initialBitrate = initialBitrate;\n this.isMonitor = isMonitor;\n this.recordingFilename = recordingFilename;\n this.disconnectingPromise = null;\n this.connectingPromise = new Promise(function (resolve, reject) {\n _this11.emit('joining', true);\n\n _this11.ws = new WebSocket(_this11.server, 'janus-protocol');\n _this11.__connectionClosedBoundFn = _this11._connectionClosed.bind(_this11);\n _this11.__handleWsEventsBoundFn = _this11._handleWsEvents.bind(_this11);\n\n _this11.ws.addEventListener('close', _this11.__connectionClosedBoundFn);\n\n _this11.ws.addEventListener('message', _this11.__handleWsEventsBoundFn);\n\n _this11.ws.onopen = function () {\n _this11._retries = 0;\n\n _this11._send({\n \"janus\": \"create\"\n }).then(function (json) {\n _this11.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n _this11._startKeepAlive();\n\n return 1;\n }).then(function () {\n return _this11._createParticipant(userId);\n }).then(function (handle) {\n _this11.handleId = handle.handleId;\n return 1;\n }).then(function () {\n return _this11._joinRoom(roomId, pin, userId);\n }).then(function () {\n _this11.connectingPromise = null;\n\n _this11.emit('joining', false);\n\n resolve(_this11);\n }).catch(function (error) {\n _this11.connectingPromise = null;\n\n _this11.emit('joining', false);\n\n reject({\n type: 'error',\n id: 13,\n message: 'connection error',\n data: error\n });\n });\n };\n\n _this11.ws.onerror = function (e) {\n _this11.connectingPromise = null;\n\n _this11.emit('joining', false);\n\n reject({\n type: 'error',\n id: 14,\n message: 'ws connection error',\n data: e\n });\n };\n });\n return this.connectingPromise;\n }\n }, {\n key: \"disconnect\",\n value: function disconnect() {\n var _this12 = this;\n\n if (this.disconnectingPromise) {\n return this.disconnectingPromise;\n }\n\n clearTimeout(this._messageTimeoutId);\n clearTimeout(this._dataChannelTimeoutId);\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = Promise.all(this._participants.map(function (p) {\n return _this12._removeParticipant(p.handleId);\n })).finally(function () {\n _this12._wipeListeners();\n\n if (_this12.ws && _this12.ws.readyState === 1) {\n _this12._send({\n \"janus\": \"destroy\"\n }, true);\n\n _this12.ws.close();\n }\n\n _this12.sessionId = null; //TODO: Just in case something crashed along the way\n\n _this12._isPublished = false;\n _this12._hasJoined = false;\n\n _this12.emit('published', {\n status: false,\n hasStream: false\n });\n\n _this12.emit('joined', false);\n\n _this12.emit('disconnect');\n\n return Promise.resolve('Disconnected');\n });\n return this.disconnectingPromise;\n }\n }, {\n key: \"startStream\",\n value: function startStream(streamId, server, iceServers, token, userId) {\n var _this13 = this;\n\n if (this.connectingPromise) {\n return this.connectingPromise;\n }\n\n this.emit('streaming', false);\n\n if (this.ws) {\n this._wipeListeners();\n }\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = null;\n this.sessionId = null;\n this.server = server;\n this.iceServers = iceServers;\n this.token = token;\n this.streamId = streamId;\n this.userId = userId;\n this.connectingPromise = new Promise(function (resolve, reject) {\n _this13.emit('streamStarting', true);\n\n _this13.ws = new WebSocket(_this13.server, 'janus-protocol');\n _this13.__connectionClosedBoundFn = _this13._connectionClosed.bind(_this13);\n _this13.__handleWsEventsBoundFn = _this13._handleWsEvents.bind(_this13);\n\n _this13.ws.addEventListener('close', _this13.__connectionClosedBoundFn);\n\n _this13.ws.addEventListener('message', _this13.__handleWsEventsBoundFn);\n\n _this13.ws.onopen = function () {\n _this13._retries = 0;\n\n _this13._send({\n \"janus\": \"create\"\n }).then(function (json) {\n _this13.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n _this13._startKeepAlive();\n\n return 1;\n }).then(function () {\n return _this13._createParticipant(userId);\n }).then(function (handle) {\n _this13.handleId = handle.handleId;\n return 1;\n }).then(function () {\n return _this13._watchStream(streamId);\n }).then(function () {\n _this13.connectingPromise = null;\n\n _this13.emit('streamStarting', false);\n\n resolve(_this13);\n }).catch(function (error) {\n _this13.connectingPromise = null;\n\n _this13.emit('streamStarting', false);\n\n reject({\n type: 'error',\n id: 13,\n message: 'connection error',\n data: error\n });\n });\n };\n\n _this13.ws.onerror = function (e) {\n _this13.connectingPromise = null;\n\n _this13.emit('streamStarting', false);\n\n reject({\n type: 'error',\n id: 14,\n message: 'ws connection error',\n data: e\n });\n };\n });\n return this.connectingPromise;\n }\n }, {\n key: \"stopStream\",\n value: function stopStream() {\n var _this14 = this;\n\n if (this.disconnectingPromise) {\n return this.disconnectingPromise;\n }\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = this.sendMessage(this.handleId, {\n body: {\n \"request\": \"stop\"\n }\n }, false, true).then(function () {\n return _this14._removeParticipant(_this14.handleId);\n }).finally(function () {\n _this14._wipeListeners();\n\n _this14._send({\n \"janus\": \"destroy\"\n }, true);\n\n if (_this14.ws && _this14.ws.readyState === 1) {\n _this14.ws.close();\n }\n\n _this14.sessionId = null;\n _this14._isStreaming = false;\n\n _this14.emit('streaming', false); // last event\n\n\n _this14.emit('disconnect');\n\n _this14.disconnectingPromise = null;\n return Promise.resolve('Disconnected');\n });\n return this.disconnectingPromise;\n }\n }, {\n key: \"destroy\",\n value: function destroy() {\n var _this15 = this;\n\n if (this.sessiontype === 'reactooroom') {\n return this.disconnect().then(function () {\n _this15.clear();\n\n return true;\n });\n } else if (this.sessiontype === 'streaming') {\n return this.stopStream().then(function () {\n _this15.clear();\n\n return true;\n });\n }\n }\n }, {\n key: \"_enableDebug\",\n value: function _enableDebug() {\n this._log = console.log.bind(console);\n }\n }, {\n key: \"_getHandle\",\n value: function _getHandle(handleId) {\n var rfid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n return this._participants.find(function (p) {\n return p.handleId === handleId || rfid && p.rfid === rfid;\n });\n }\n }, {\n key: \"_getStats\",\n value: function _getStats() {\n var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n return Promise.all(this._participants.map(function (participant) {\n var 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(function (r) {\n return {\n handle: participant,\n stats: r\n };\n }).catch(function (e) {\n return Promise.resolve({\n handle: participant,\n stats: e\n });\n });\n }));\n }\n }, {\n key: \"_sendTrickleCandidate\",\n value: function _sendTrickleCandidate(handleId, candidate) {\n return this._send({\n \"janus\": \"trickle\",\n \"candidate\": candidate,\n \"handle_id\": handleId\n });\n }\n }, {\n key: \"_webrtc\",\n value: function _webrtc(handleId) {\n var _this16 = this;\n\n var enableOntrack = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n var 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 var config = handle.webrtcStuff;\n\n if (!config.pc) {\n var pc_config = {\n \"iceServers\": this.iceServers,\n \"iceTransportPolicy\": 'all',\n \"bundlePolicy\": undefined\n };\n pc_config[\"sdpSemantics\"] = this.isUnifiedPlan ? \"unified-plan\" : \"plan-b\";\n var 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 = function () {\n if (config.pc.connectionState === 'failed') {\n _this16._iceRestart(handleId);\n }\n\n _this16.emit('connectionState', [handleId, handleId === _this16.handleId, config.pc.connectionState]);\n\n if (handleId !== _this16.handleId && config.pc.connectionState === 'connected') {\n _this16.emit(_this16._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n stream: config.stream,\n track: null,\n optional: true,\n constructId: _this16.constructId,\n metaData: _this16.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 = function () {\n if (config.pc.iceConnectionState === 'failed') {\n _this16._iceRestart(handleId);\n }\n\n _this16.emit('iceState', [handleId, handleId === _this16.handleId, config.pc.iceConnectionState]);\n\n if (handleId !== _this16.handleId && (config.pc.iceConnectionState === 'completed' || config.pc.iceConnectionState === 'connected')) {\n _this16.emit(_this16._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n stream: config.stream,\n track: null,\n optional: true,\n constructId: _this16.constructId,\n metaData: _this16.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 = function (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 _this16._sendTrickleCandidate(handleId, {\n \"completed\": true\n }).catch(function (e) {\n _this16.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 _this16._sendTrickleCandidate(handleId, candidate).catch(function (e) {\n _this16.emit('error', e);\n });\n }\n };\n\n if (enableOntrack) {\n config.pc.ontrack = function (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 mid = event.transceiver ? event.transceiver.mid : event.track.id;\n config.stream.addTrack(event.track);\n\n _this16.emit(_this16._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n mid: mid,\n id: handle.handleId,\n userId: handle.userId,\n stream: config.stream,\n track: event.track,\n constructId: _this16.constructId,\n metaData: _this16.options.metaData,\n adding: true,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n\n if (event.track.onended) return;\n\n event.track.onended = function (ev) {\n var mid = ev.target.id;\n\n if (_this16.isUnifiedPlan) {\n var transceiver = config.pc.getTransceivers().find(function (t) {\n return t.receiver.track === ev.target;\n });\n mid = transceiver.mid;\n }\n\n if (config.stream) {\n config.stream && config.stream.removeTrack(ev.target);\n\n _this16.emit(_this16._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n mid: mid,\n userId: handle.userId,\n stream: config.stream,\n track: ev.target,\n constructId: _this16.constructId,\n metaData: _this16.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 = function (ev) {\n _this16._log('remoteTrackMuted', 'onmute');\n\n var mid = ev.target.id;\n\n if (_this16.isUnifiedPlan) {\n var transceiver = config.pc.getTransceivers().find(function (t) {\n return t.receiver.track === ev.target;\n });\n mid = transceiver.mid;\n }\n\n _this16.emit('remoteTrackMuted', {\n id: handle.handleId,\n mid: mid,\n userId: handle.userId,\n stream: config.stream,\n kind: ev.target.kind,\n track: ev.target,\n muted: true\n });\n };\n\n event.track.onunmute = function (ev) {\n _this16._log('remoteTrackMuted', 'onunmute');\n\n var mid = ev.target.id;\n\n if (_this16.isUnifiedPlan) {\n var transceiver = config.pc.getTransceivers().find(function (t) {\n return t.receiver.track === ev.target;\n });\n mid = transceiver.mid;\n }\n\n _this16.emit('remoteTrackMuted', {\n id: handle.handleId,\n mid: mid,\n userId: handle.userId,\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 = function onDataChannelMessage(event) {\n _this16._handleDataEvents(handleId, 'message', event.data);\n };\n\n var onDataChannelStateChange = function onDataChannelStateChange(event) {\n var label = event.target.label;\n var protocol = event.target.protocol;\n var state = config.dataChannel[label] ? config.dataChannel[label].readyState : \"null\";\n\n _this16._handleDataEvents(handleId, 'state', {\n state: state,\n label: label\n });\n }; //TODO: check this\n\n\n var onDataChannelError = function onDataChannelError(error) {\n var _error$channel;\n\n _this16._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: error\n });\n };\n\n var createDataChannel = function createDataChannel(label, protocol, incoming) {\n var options = {\n ordered: true\n };\n\n if (!incoming) {\n if (protocol) {\n options = _objectSpread(_objectSpread({}, options), {}, {\n protocol: 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 key: \"_webrtcPeer\",\n value: function _webrtcPeer(handleId, jsep) {\n var 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(function () {\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 key: \"_iceRestart\",\n value: function _iceRestart(handleId) {\n var _this17 = this;\n\n var 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 var hasAudio = !!(config.stream && config.stream.getAudioTracks().length > 0);\n var hasVideo = !!(config.stream && config.stream.getVideoTracks().length > 0);\n\n this._createAO('offer', handleId, true, [hasAudio, false, hasVideo, false]).then(function (jsep) {\n if (!jsep) {\n return null;\n }\n\n return _this17.sendMessage(handleId, {\n body: _objectSpread({\n \"request\": \"configure\",\n \"audio\": hasAudio,\n \"video\": hasVideo,\n \"data\": true\n }, _this17.recordingFilename ? {\n filename: _this17.recordingFilename\n } : {}),\n jsep: jsep\n });\n }).then(function (r) {\n config.isIceRestarting = false;\n\n _this17._log('ICE restart success');\n }).catch(function (e) {\n config.isIceRestarting = false;\n\n _this17.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(function () {\n config.isIceRestarting = false;\n }).catch(function () {\n config.isIceRestarting = false;\n });\n }\n }\n }, {\n key: \"_createAO\",\n value: function _createAO() {\n var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'offer';\n var handleId = arguments.length > 1 ? arguments[1] : undefined;\n var iceRestart = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n\n var _ref = arguments.length > 3 ? arguments[3] : undefined,\n _ref2 = _slicedToArray(_ref, 4),\n audioSend = _ref2[0],\n audioRecv = _ref2[1],\n videoSend = _ref2[2],\n videoRecv = _ref2[3];\n\n var 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 var 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 var _p = config.pc.setLocalDescription(response).catch(function (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(function () {\n return jsep;\n });\n }, function (e) {\n return Promise.reject({\n type: 'warning',\n id: 25,\n message: methodName,\n data: [handleId, e]\n });\n });\n }\n }, {\n key: \"_publishRemote\",\n value: function _publishRemote(handleId, jsep) {\n var _this18 = this;\n\n var 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 var config = handle.webrtcStuff;\n\n if (jsep) {\n return config.pc.setRemoteDescription(jsep).then(function () {\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 _this18._createAO('answer', handleId, false, [false, true, false, true]).then(function (_jsep) {\n if (!_jsep) {\n _this18.emit('error', {\n type: 'warning',\n id: 19,\n message: 'publish remote participant',\n data: [handleId, 'no jsep']\n });\n\n return Promise.resolve();\n }\n\n return _this18.sendMessage(handleId, {\n \"body\": _objectSpread(_objectSpread({\n \"request\": \"start\"\n }, _this18.roomId && {\n \"room\": _this18.roomId\n }), _this18.pin && {\n pin: _this18.pin\n }),\n \"jsep\": _jsep\n });\n });\n }, function (e) {\n return Promise.reject({\n type: 'warning',\n id: 23,\n message: 'setRemoteDescription',\n data: [handleId, e]\n });\n });\n } else {\n return Promise.resolve();\n }\n } //Public methods\n\n }, {\n key: \"publishLocal\",\n value: function publishLocal(stream) {\n var _this19 = this;\n\n var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n _ref3$keepAudio = _ref3.keepAudio,\n keepAudio = _ref3$keepAudio === void 0 ? false : _ref3$keepAudio,\n _ref3$keepVideo = _ref3.keepVideo,\n keepVideo = _ref3$keepVideo === void 0 ? false : _ref3$keepVideo;\n\n this.emit('publishing', true);\n\n var 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 var 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 var replaceAudio = stream.getAudioTracks().length;\n\n if (replaceAudio || !keepAudio) {\n //this will stop existing tracks\n var 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 (var index in config.pc.getSenders()) {\n var 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 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 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 var replaceVideo = stream.getVideoTracks().length;\n\n if (replaceVideo || !keepVideo) {\n var 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 (var _index in config.pc.getSenders()) {\n var _s2 = config.pc.getSenders()[_index];\n\n if (_s2 && _s2.track && _s2.track.kind === \"video\") {\n config.pc.removeTrack(_s2);\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 var _transceivers = config.pc.getTransceivers();\n\n if (_transceivers && _transceivers.length > 0) {\n for (var _i2 in _transceivers) {\n var _t = _transceivers[_i2];\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 var hasAudio = !!(stream && stream.getAudioTracks().length > 0);\n var hasVideo = !!(stream && stream.getVideoTracks().length > 0);\n var isAudioMuted = !stream || stream.getAudioTracks().length === 0 || !stream.getAudioTracks()[0].enabled;\n var 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(function (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 _this19.sendMessage(_this19.handleId, {\n body: _objectSpread({\n \"request\": \"configure\",\n \"audio\": hasAudio,\n \"video\": hasVideo,\n \"data\": true\n }, _this19.recordingFilename ? {\n filename: _this19.recordingFilename\n } : {}),\n jsep: jsep\n });\n }).then(function (r) {\n if (_this19._isDataChannelOpen) {\n return Promise.resolve(r);\n } else {\n return new Promise(function (resolve, reject) {\n var __ = function __(val) {\n if (val) {\n clearTimeout(_this19._dataChannelTimeoutId);\n\n _this19.off('dataChannel', __, _this19);\n\n resolve(_this19);\n }\n };\n\n _this19._dataChannelTimeoutId = setTimeout(function () {\n _this19.off('dataChannel', __, _this19);\n\n reject({\n type: 'error',\n id: 27,\n message: 'Data channel did not open',\n data: null\n });\n }, 5000);\n\n _this19.on('dataChannel', __, _this19);\n });\n }\n }).then(function (r) {\n _this19._isPublished = true;\n\n if (config.stream) {\n var tracks = config.stream.getTracks();\n tracks.forEach(function (track) {\n // used as a flag to not emit tracks that been already emitted\n if (!track.onended) {\n _this19.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n track: track,\n stream: config.stream,\n adding: true,\n constructId: _this19.constructId,\n metaData: _this19.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n\n track.onended = function (ev) {\n _this19.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n track: ev.target,\n stream: config.stream,\n adding: false,\n removing: true,\n constructId: _this19.constructId,\n metaData: _this19.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n };\n }\n });\n } else {\n _this19.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n stream: null,\n adding: false,\n constructId: _this19.constructId,\n metaData: _this19.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n }\n\n _this19.emit('published', {\n status: true,\n hasStream: !!config.stream\n });\n\n _this19.emit('publishing', false);\n\n _this19.emit('localHasVideo', hasVideo);\n\n _this19.emit('localHasAudio', hasAudio);\n\n _this19.emit('localMuted', {\n type: 'video',\n value: isVideoMuted\n });\n\n _this19.emit('localMuted', {\n type: 'audio',\n value: isAudioMuted\n });\n\n return r;\n }).catch(function (e) {\n _this19.emit('publishing', false);\n\n return Promise.reject(e);\n });\n }\n }, {\n key: \"unpublishLocal\",\n value: function unpublishLocal() {\n var _this20 = this;\n\n var 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(function (r) {\n _this20._isPublished = false;\n\n _this20.emit('published', {\n status: false,\n hasStream: false\n });\n\n return r;\n }) : Promise.resolve();\n }\n }, {\n key: \"toggleAudio\",\n value: function toggleAudio() {\n var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n var mid = arguments.length > 1 ? arguments[1] : undefined;\n\n var 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 var config = handle.webrtcStuff;\n\n if (this.isUnifiedPlan) {\n var transceiver = config.pc.getTransceivers().find(function (t) {\n return t.sender && t.sender.track && t.receiver.track.kind === \"audio\" && t.stopped === false && (mid ? t.mid === mid : true);\n });\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: mid\n });\n }\n }, {\n key: \"toggleVideo\",\n value: function toggleVideo() {\n var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n var mid = arguments.length > 1 ? arguments[1] : undefined;\n\n var 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 var config = handle.webrtcStuff;\n\n if (this.isUnifiedPlan) {\n var transceiver = config.pc.getTransceivers().find(function (t) {\n return t.sender && t.sender.track && t.receiver.track.kind === \"video\" && t.stopped === false && (mid ? t.mid === mid : true);\n });\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: mid\n });\n }\n }, {\n key: \"setInstructorId\",\n value: function setInstructorId() {\n var instructorId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n this._instuctorId = instructorId;\n this.emit('instructorId', this._instuctorId);\n return this._instuctorId;\n }\n }, {\n key: \"setObserverIds\",\n value: function setObserverIds() {\n var observerIds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n this._observerIds = observerIds;\n this.emit('observerIds', this._observerIds);\n return this._observerIds;\n }\n }, {\n key: \"setTalkbackIds\",\n value: function setTalkbackIds() {\n var talkbackIds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n this._talkbackIds = talkbackIds;\n this.emit('talkbackIds', this._talkbackIds);\n return this._talkbackIds;\n }\n }], [{\n key: \"noop\",\n value: function noop() {}\n }, {\n key: \"randomString\",\n value: function 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 key: \"checkUnifiedPlan\",\n value: function checkUnifiedPlan() {\n var 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 var 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\n return RoomSession;\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 watchTogether: ['participant', 'talkback'],\n videoWall: ['instructor', 'observer', 'talkback']\n },\n monitor: {\n watchTogether: ['participant'],\n videoWall: ['instructor', 'participant']\n },\n talkback: {\n watchTogether: ['participant'],\n videoWall: ['instructor', 'participant']\n },\n observer: {\n watchTogether: ['participant'],\n videoWall: ['participant']\n },\n instructor: {\n watchTogether: [],\n videoWall: []\n }\n});\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Room);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-room.js?");
9384
+ 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 _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\nfunction _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\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\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\n// Watch together janus webrtc library\n\n\n\n\nvar Room = /*#__PURE__*/function () {\n function Room(debug) {\n var _this = this;\n\n _classCallCheck(this, Room);\n\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(function (safariVp8) {\n _this.safariVp8 = safariVp8;\n }); // Let's get it started\n\n this.whenInitialized = this.initialize();\n }\n\n _createClass(Room, [{\n key: \"initialize\",\n value: function initialize() {\n var _this2 = this;\n\n return this.safariVp8TestPromise.then(function () {\n return _this2;\n });\n }\n }, {\n key: \"createSession\",\n value: function createSession() {\n var constructId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'reactooroom';\n var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n return new RoomSession(constructId, type, _objectSpread({\n debug: this.debug\n }, options));\n }\n }], [{\n key: \"testSafariVp8\",\n value: function testSafariVp8() {\n return new Promise(function (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 var 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 key: \"isWebrtcSupported\",\n value: function 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 return Room;\n}();\n\nvar RoomSession = /*#__PURE__*/function () {\n function RoomSession() {\n var constructId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'reactooroom';\n var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n _classCallCheck(this, RoomSession);\n\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; //TODO: remove this\n\n this.isMonitor = false; // currently used just for classroom context so monitor user only subscribes to participants and not trainer (for other monitor this flag is not necessary)\n\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; //TODO: do it better\n // double click prevention\n\n this.connectingPromise = null;\n this.disconnectingPromise = null;\n this._ipv6Support = false;\n this._retries = 0;\n this._maxRetries = 3;\n this._keepAliveId = null;\n this._participants = [];\n this._observerIds = [];\n this._talkbackIds = [];\n this._instuctorId = null;\n this._hasJoined = false;\n this._isStreaming = false;\n this._isPublished = false;\n this._isDataChannelOpen = false;\n this._dataChannelTimeoutId = null;\n this._messageTimeoutId = 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 = _objectSpread(_objectSpread({}, RoomSession.subscriptionRules), this.options.subscriptionRules || {});\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 _createClass(RoomSession, [{\n key: \"_participantShouldSubscribe\",\n value: function _participantShouldSubscribe(userId) {\n var allowedObservers = this._observerIds || [];\n var allowedTalkback = this._talkbackIds || [];\n var allowedInstructor = this._instuctorId || null;\n var localUserRole = 'participant';\n\n if (this.isMonitor) {\n localUserRole = 'monitor';\n } else if (allowedObservers.indexOf(this.userId) > -1) {\n localUserRole = 'observer';\n } else if (allowedTalkback.indexOf(this.userId) > -1) {\n localUserRole = 'talkback';\n } else if (this.userId === allowedInstructor) {\n localUserRole = 'instructor';\n }\n\n var remoteUserRole = 'participant';\n\n if (allowedObservers.indexOf(userId) > -1) {\n remoteUserRole = 'observer';\n } else if (allowedTalkback.indexOf(userId) > -1) {\n remoteUserRole = 'talkback';\n } else if (userId === allowedInstructor) {\n remoteUserRole = 'instructor';\n }\n\n var mode = allowedInstructor !== null ? 'videoWall' : 'watchTogether';\n return this.subscriptionRules[localUserRole][mode].indexOf(remoteUserRole) > -1;\n }\n }, {\n key: \"_getAddParticipantEventName\",\n value: function _getAddParticipantEventName(handleId) {\n var 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 var allowedTalkback = this._talkbackIds || [];\n var allowedObservers = this._observerIds || [];\n var allowedInstructor = this._instuctorId || null;\n var eventName = 'addRemoteParticipant';\n\n if (handle.userId === allowedInstructor) {\n eventName = 'addRemoteInstructor';\n }\n\n if (allowedTalkback.indexOf(handle.userId) > -1) {\n eventName = 'addRemoteTalkback';\n }\n\n if (allowedObservers.indexOf(handle.userId) > -1) {\n eventName = 'addRemoteObserver';\n }\n\n return eventName;\n }\n }, {\n key: \"_getRemoveParticipantEventName\",\n value: function _getRemoveParticipantEventName(handleId) {\n var 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 var allowedTalkback = this._talkbackIds || [];\n var allowedObservers = this._observerIds || [];\n var allowedInstructor = this._instuctorId || null;\n var eventName = 'removeRemoteParticipant';\n\n if (handle.userId === allowedInstructor) {\n eventName = 'removeRemoteInstructor';\n }\n\n if (allowedTalkback.indexOf(handle.userId) > -1) {\n eventName = 'removeRemoteTalkback';\n }\n\n if (allowedObservers.indexOf(handle.userId) > -1) {\n eventName = 'removeRemoteObserver';\n }\n\n return eventName;\n }\n }, {\n key: \"sendMessage\",\n value: function sendMessage(handleId) {\n var message = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n body: 'Example Body'\n };\n var dontWait = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n var dontResolveOnAck = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n return this._send(_objectSpread({\n \"janus\": \"message\",\n \"handle_id\": handleId\n }, message), dontWait, dontResolveOnAck).then(function (json) {\n if (json && json[\"janus\"] === \"success\") {\n var plugindata = json[\"plugindata\"] || {};\n var data = plugindata[\"data\"];\n return Promise.resolve(data);\n }\n\n return Promise.resolve();\n }).catch(function (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 key: \"_send\",\n value: function _send() {\n var _this3 = this;\n\n var request = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var ignoreResponse = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n var dontResolveOnAck = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n var transaction = RoomSession.randomString(12);\n\n var requestData = _objectSpread(_objectSpread({}, request), {}, {\n transaction: transaction,\n token: this.token\n }, this.sessionId && {\n 'session_id': this.sessionId\n } || {});\n\n return new Promise(function (resolve, reject) {\n var parseResponse = function parseResponse(event) {\n var json = JSON.parse(event.data);\n var r_transaction = json['transaction'];\n\n if (r_transaction === transaction && (!dontResolveOnAck || json['janus'] !== 'ack')) {\n clearTimeout(_this3._messageTimeoutId);\n\n _this3.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 _this3.disconnect(true);\n }\n\n reject({\n type: 'error',\n id: 2,\n message: 'send failed',\n data: json,\n requestData: requestData\n });\n } else {\n resolve(json);\n }\n }\n };\n\n if (ignoreResponse) {\n if (_this3.ws && _this3.ws.readyState === 1) {\n _this3.ws.send(JSON.stringify(requestData));\n }\n\n resolve();\n } else {\n if (_this3.ws && _this3.ws.readyState === 1) {\n _this3.ws.addEventListener('message', parseResponse);\n\n _this3._messageTimeoutId = setTimeout(function () {\n _this3.ws.removeEventListener('message', parseResponse);\n\n reject({\n type: 'error',\n id: 3,\n message: 'send timeout',\n data: requestData\n });\n }, 10000);\n\n _this3.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 key: \"_connectionClosed\",\n value: function _connectionClosed() {\n var _this4 = this;\n\n if (this.disconnectingPromise || this.connectingPromise) {\n return;\n }\n\n if (this._retries < this._maxRetries) {\n setTimeout(function () {\n _this4._retries++;\n\n _this4._reconnect().catch(function (e) {\n _this4.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 key: \"_wipeListeners\",\n value: function _wipeListeners() {\n if (this.ws) {\n this.ws.removeEventListener('close', this.__connectionClosedBoundFn);\n this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);\n }\n }\n }, {\n key: \"_startKeepAlive\",\n value: function _startKeepAlive() {\n var _this5 = this;\n\n this._send({\n \"janus\": \"keepalive\"\n }).then(function (json) {\n if (json[\"janus\"] !== 'ack') {\n _this5.emit('error', {\n type: 'warning',\n id: 5,\n message: 'keepalive response suspicious',\n data: json[\"janus\"]\n });\n }\n }).catch(function (e) {\n _this5.emit('error', {\n type: 'warning',\n id: 6,\n message: 'keepalive dead',\n data: e\n });\n\n _this5._connectionClosed();\n });\n\n this._keepAliveId = setTimeout(function () {\n _this5._startKeepAlive();\n }, 30000);\n }\n }, {\n key: \"_stopKeepAlive\",\n value: function _stopKeepAlive() {\n clearTimeout(this._keepAliveId);\n }\n }, {\n key: \"_handleWsEvents\",\n value: function _handleWsEvents(event) {\n var _this6 = this;\n\n var json = JSON.parse(event.data);\n var sender = json[\"sender\"];\n var type = json[\"janus\"];\n\n var handle = this._getHandle(sender);\n\n if (!handle) {\n return;\n }\n\n if (type === \"trickle\") {\n var candidate = json[\"candidate\"];\n var 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 var result = msg[\"result\"] || null;\n\n var _event = msg[\"videoroom\"] || null;\n\n var list = msg[\"publishers\"] || {};\n var leaving = msg[\"leaving\"]; //let joining = msg[\"joining\"];\n\n var unpublished = msg[\"unpublished\"];\n var error = msg[\"error\"];\n\n if (_event === \"joined\") {\n this.id = msg[\"id\"];\n this.privateId = msg[\"private_id\"];\n this._hasJoined = true;\n this.emit('joined', true);\n\n this._log('We have successfully joined Room');\n\n var _loop = function _loop(f) {\n var userId = list[f][\"display\"];\n var streams = list[f][\"streams\"] || [];\n var id = list[f][\"id\"];\n\n for (var i in streams) {\n streams[i][\"id\"] = id;\n streams[i][\"display\"] = userId;\n }\n\n _this6._log('Remote userId: ', userId);\n\n if (_this6._participantShouldSubscribe(userId)) {\n _this6._log('Creating user: ', userId);\n\n _this6._createParticipant(userId, id).then(function (handle) {\n return _this6.sendMessage(handle.handleId, {\n body: _objectSpread(_objectSpread({\n \"request\": \"join\",\n \"room\": _this6.roomId,\n \"ptype\": \"subscriber\",\n \"feed\": id,\n \"private_id\": _this6.privateId\n }, _this6.webrtcVersion > 1000 ? {\n id: _this6.userId\n } : {}), {}, {\n pin: _this6.pin\n })\n });\n }).catch(function (err) {\n _this6.emit('error', err);\n });\n }\n };\n\n for (var f in list) {\n _loop(f);\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 var _loop2 = function _loop2(_f) {\n var userId = list[_f][\"display\"];\n var streams = list[_f][\"streams\"] || [];\n var id = list[_f][\"id\"];\n\n for (var i in streams) {\n streams[i][\"id\"] = id;\n streams[i][\"display\"] = userId;\n }\n\n _this6._log('Remote userId: ', userId);\n\n if (_this6._participantShouldSubscribe(userId)) {\n _this6._log('Creating user: ', userId);\n\n _this6._createParticipant(userId, id).then(function (handle) {\n return _this6.sendMessage(handle.handleId, {\n body: _objectSpread(_objectSpread({\n \"request\": \"join\",\n \"room\": _this6.roomId,\n \"ptype\": \"subscriber\",\n \"feed\": id,\n \"private_id\": _this6.privateId\n }, _this6.webrtcVersion > 1000 ? {\n id: _this6.userId\n } : {}), {}, {\n pin: _this6.pin\n })\n });\n }).catch(function (err) {\n _this6.emit('error', err);\n });\n }\n };\n\n for (var _f in list) {\n _loop2(_f);\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(function () {});\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(function (err) {\n _this6.emit('error', err);\n });\n } else if (this.sessiontype === 'streaming') {\n this._publishRemote(this.handleId, jsep).catch(function (err) {\n _this6.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(function () {\n return null;\n });\n }\n }\n } //REMOTE\n else {\n var _plugindata = json[\"plugindata\"] || {};\n\n var _msg = _plugindata[\"data\"] || {};\n\n var _jsep2 = json[\"jsep\"];\n var _event2 = _msg[\"videoroom\"];\n var _error = _msg[\"error\"];\n\n if (_event2 === \"attached\") {\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: handle.userId,\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 (_jsep2) {\n this._publishRemote(handle.handleId, _jsep2).catch(function (err) {\n _this6.emit('error', err);\n });\n }\n }\n }\n }, {\n key: \"_handleDataEvents\",\n value: function _handleDataEvents(handleId, type, data) {\n var 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 var 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 var _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 var 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 key: \"_removeParticipant\",\n value: function _removeParticipant(handleId, rfid) {\n var _this7 = this;\n\n var removeHandle = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n\n var 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(function () {\n return removeHandle ? _this7._send({\n \"janus\": \"detach\",\n \"handle_id\": handleId\n }, true) : Promise.resolve();\n }).finally(function () {\n try {\n if (handle.webrtcStuff.stream && !_this7.isRestarting) {\n handle.webrtcStuff.stream.getTracks().forEach(function (track) {\n return track.stop();\n });\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(function (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 === _this7.handleId) {\n _this7._isDataChannelOpen = false;\n _this7._isPublished = false;\n\n _this7.emit('published', {\n status: false,\n hasStream: false\n });\n\n _this7.emit('removeLocalParticipant', {\n id: handleId,\n userId: handle.userId\n });\n } else {\n _this7.emit(_this7._getRemoveParticipantEventName(handleId), {\n id: handleId,\n userId: handle.userId\n });\n }\n\n if (removeHandle) {\n var handleIndex = _this7._participants.findIndex(function (p) {\n return p.handleId === handleId;\n });\n\n _this7._participants.splice(handleIndex, 1);\n }\n\n return true;\n });\n }\n }, {\n key: \"_createParticipant\",\n value: function _createParticipant() {\n var _this8 = this;\n\n var userId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n var rfid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n return this._send({\n \"janus\": \"attach\",\n \"plugin\": this.pluginName\n }).then(function (json) {\n var handleId = json.data[\"id\"];\n var handle = {\n handleId: handleId,\n rfid: rfid,\n userId: 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 _this8._participants.push(handle);\n\n return handle;\n });\n }\n }, {\n key: \"_joinRoom\",\n value: function _joinRoom(roomId, pin, userId, display) {\n return this.sendMessage(this.handleId, {\n body: _objectSpread({\n \"request\": \"join\",\n \"room\": roomId,\n \"pin\": pin,\n \"ptype\": \"publisher\",\n \"display\": display\n }, this.webrtcVersion > 1000 ? {\n id: userId\n } : {})\n }, false, true);\n }\n }, {\n key: \"_watchStream\",\n value: function _watchStream(id) {\n return this.sendMessage(this.handleId, {\n body: {\n \"request\": \"watch\",\n id: parseInt(id)\n }\n }, false, true);\n }\n }, {\n key: \"_leaveRoom\",\n value: function _leaveRoom() {\n var _this9 = this;\n\n var dontWait = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n return this._hasJoined ? this.sendMessage(this.handleId, {\n body: {\n \"request\": \"leave\"\n }\n }, dontWait).finally(function () {\n _this9._hasJoined = false;\n\n _this9.emit('joined', false);\n }) : Promise.resolve();\n } // internal reconnect\n\n }, {\n key: \"_reconnect\",\n value: function _reconnect() {\n var _this10 = this;\n\n if (this.connectingPromise) {\n return this.connectingPromise;\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.connectingPromise = new Promise(function (resolve, reject) {\n _this10.emit('joining', true);\n\n _this10.ws = new WebSocket(_this10.server, 'janus-protocol');\n _this10.__connectionClosedBoundFn = _this10._connectionClosed.bind(_this10);\n _this10.__handleWsEventsBoundFn = _this10._handleWsEvents.bind(_this10);\n\n _this10.ws.addEventListener('close', _this10.__connectionClosedBoundFn);\n\n _this10.ws.addEventListener('message', _this10.__handleWsEventsBoundFn);\n\n _this10.ws.onopen = function () {\n _this10._send({\n \"janus\": \"claim\"\n }).then(function (json) {\n _this10.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n _this10._startKeepAlive();\n\n _this10.connectingPromise = null;\n\n _this10.emit('joining', false);\n\n _this10._retries = 0;\n resolve(json);\n }).catch(function (error) {\n _this10.connectingPromise = null;\n\n _this10.emit('joining', false);\n\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 _this10.ws.onerror = function (e) {\n _this10.connectingPromise = null;\n\n _this10.emit('joining', false);\n\n reject({\n type: 'warning',\n id: 12,\n message: 'ws reconnection error',\n data: e\n });\n };\n });\n return this.connectingPromise;\n }\n }, {\n key: \"connect\",\n value: function connect(roomId, pin, server, iceServers, token, display, userId) {\n var _this11 = this;\n\n var webrtcVersion = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 0;\n var initialBitrate = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : 0;\n var isMonitor = arguments.length > 9 ? arguments[9] : undefined;\n var recordingFilename = arguments.length > 10 ? arguments[10] : undefined;\n\n if (this.connectingPromise) {\n return this.connectingPromise;\n }\n\n this.emit('joined', false);\n\n if (this.ws) {\n this._wipeListeners();\n }\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = null;\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.isMonitor = isMonitor;\n this.recordingFilename = recordingFilename;\n this.disconnectingPromise = null;\n this.connectingPromise = new Promise(function (resolve, reject) {\n _this11.emit('joining', true);\n\n _this11.ws = new WebSocket(_this11.server, 'janus-protocol');\n _this11.__connectionClosedBoundFn = _this11._connectionClosed.bind(_this11);\n _this11.__handleWsEventsBoundFn = _this11._handleWsEvents.bind(_this11);\n\n _this11.ws.addEventListener('close', _this11.__connectionClosedBoundFn);\n\n _this11.ws.addEventListener('message', _this11.__handleWsEventsBoundFn);\n\n _this11.ws.onopen = function () {\n _this11._retries = 0;\n\n _this11._send({\n \"janus\": \"create\"\n }).then(function (json) {\n _this11.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n _this11._startKeepAlive();\n\n return 1;\n }).then(function () {\n return _this11._createParticipant(userId);\n }).then(function (handle) {\n _this11.handleId = handle.handleId;\n return 1;\n }).then(function () {\n return _this11._joinRoom(roomId, pin, userId, display);\n }).then(function () {\n _this11.connectingPromise = null;\n\n _this11.emit('joining', false);\n\n resolve(_this11);\n }).catch(function (error) {\n _this11.connectingPromise = null;\n\n _this11.emit('joining', false);\n\n reject({\n type: 'error',\n id: 13,\n message: 'connection error',\n data: error\n });\n });\n };\n\n _this11.ws.onerror = function (e) {\n _this11.connectingPromise = null;\n\n _this11.emit('joining', false);\n\n reject({\n type: 'error',\n id: 14,\n message: 'ws connection error',\n data: e\n });\n };\n });\n return this.connectingPromise;\n }\n }, {\n key: \"disconnect\",\n value: function disconnect() {\n var _this12 = this;\n\n if (this.disconnectingPromise) {\n return this.disconnectingPromise;\n }\n\n clearTimeout(this._messageTimeoutId);\n clearTimeout(this._dataChannelTimeoutId);\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = Promise.all(this._participants.map(function (p) {\n return _this12._removeParticipant(p.handleId);\n })).finally(function () {\n _this12._wipeListeners();\n\n if (_this12.ws && _this12.ws.readyState === 1) {\n _this12._send({\n \"janus\": \"destroy\"\n }, true);\n\n _this12.ws.close();\n }\n\n _this12.sessionId = null; //TODO: Just in case something crashed along the way\n\n _this12._isPublished = false;\n _this12._hasJoined = false;\n\n _this12.emit('published', {\n status: false,\n hasStream: false\n });\n\n _this12.emit('joined', false);\n\n _this12.emit('disconnect');\n\n return Promise.resolve('Disconnected');\n });\n return this.disconnectingPromise;\n }\n }, {\n key: \"startStream\",\n value: function startStream(streamId, server, iceServers, token, userId) {\n var _this13 = this;\n\n if (this.connectingPromise) {\n return this.connectingPromise;\n }\n\n this.emit('streaming', false);\n\n if (this.ws) {\n this._wipeListeners();\n }\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = null;\n this.sessionId = null;\n this.server = server;\n this.iceServers = iceServers;\n this.token = token;\n this.streamId = streamId;\n this.userId = userId;\n this.connectingPromise = new Promise(function (resolve, reject) {\n _this13.emit('streamStarting', true);\n\n _this13.ws = new WebSocket(_this13.server, 'janus-protocol');\n _this13.__connectionClosedBoundFn = _this13._connectionClosed.bind(_this13);\n _this13.__handleWsEventsBoundFn = _this13._handleWsEvents.bind(_this13);\n\n _this13.ws.addEventListener('close', _this13.__connectionClosedBoundFn);\n\n _this13.ws.addEventListener('message', _this13.__handleWsEventsBoundFn);\n\n _this13.ws.onopen = function () {\n _this13._retries = 0;\n\n _this13._send({\n \"janus\": \"create\"\n }).then(function (json) {\n _this13.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n _this13._startKeepAlive();\n\n return 1;\n }).then(function () {\n return _this13._createParticipant(userId);\n }).then(function (handle) {\n _this13.handleId = handle.handleId;\n return 1;\n }).then(function () {\n return _this13._watchStream(streamId);\n }).then(function () {\n _this13.connectingPromise = null;\n\n _this13.emit('streamStarting', false);\n\n resolve(_this13);\n }).catch(function (error) {\n _this13.connectingPromise = null;\n\n _this13.emit('streamStarting', false);\n\n reject({\n type: 'error',\n id: 13,\n message: 'connection error',\n data: error\n });\n });\n };\n\n _this13.ws.onerror = function (e) {\n _this13.connectingPromise = null;\n\n _this13.emit('streamStarting', false);\n\n reject({\n type: 'error',\n id: 14,\n message: 'ws connection error',\n data: e\n });\n };\n });\n return this.connectingPromise;\n }\n }, {\n key: \"stopStream\",\n value: function stopStream() {\n var _this14 = this;\n\n if (this.disconnectingPromise) {\n return this.disconnectingPromise;\n }\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = this.sendMessage(this.handleId, {\n body: {\n \"request\": \"stop\"\n }\n }, false, true).then(function () {\n return _this14._removeParticipant(_this14.handleId);\n }).finally(function () {\n _this14._wipeListeners();\n\n _this14._send({\n \"janus\": \"destroy\"\n }, true);\n\n if (_this14.ws && _this14.ws.readyState === 1) {\n _this14.ws.close();\n }\n\n _this14.sessionId = null;\n _this14._isStreaming = false;\n\n _this14.emit('streaming', false); // last event\n\n\n _this14.emit('disconnect');\n\n _this14.disconnectingPromise = null;\n return Promise.resolve('Disconnected');\n });\n return this.disconnectingPromise;\n }\n }, {\n key: \"destroy\",\n value: function destroy() {\n var _this15 = this;\n\n if (this.sessiontype === 'reactooroom') {\n return this.disconnect().then(function () {\n _this15.clear();\n\n return true;\n });\n } else if (this.sessiontype === 'streaming') {\n return this.stopStream().then(function () {\n _this15.clear();\n\n return true;\n });\n }\n }\n }, {\n key: \"_enableDebug\",\n value: function _enableDebug() {\n this._log = console.log.bind(console);\n }\n }, {\n key: \"_getHandle\",\n value: function _getHandle(handleId) {\n var rfid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n return this._participants.find(function (p) {\n return p.handleId === handleId || rfid && p.rfid === rfid;\n });\n }\n }, {\n key: \"_getStats\",\n value: function _getStats() {\n var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n return Promise.all(this._participants.map(function (participant) {\n var 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(function (r) {\n return {\n handle: participant,\n stats: r\n };\n }).catch(function (e) {\n return Promise.resolve({\n handle: participant,\n stats: e\n });\n });\n }));\n }\n }, {\n key: \"_sendTrickleCandidate\",\n value: function _sendTrickleCandidate(handleId, candidate) {\n return this._send({\n \"janus\": \"trickle\",\n \"candidate\": candidate,\n \"handle_id\": handleId\n });\n }\n }, {\n key: \"_webrtc\",\n value: function _webrtc(handleId) {\n var _this16 = this;\n\n var enableOntrack = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n var 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 var config = handle.webrtcStuff;\n\n if (!config.pc) {\n var pc_config = {\n \"iceServers\": this.iceServers,\n \"iceTransportPolicy\": 'all',\n \"bundlePolicy\": undefined\n };\n pc_config[\"sdpSemantics\"] = this.isUnifiedPlan ? \"unified-plan\" : \"plan-b\";\n var 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 = function () {\n if (config.pc.connectionState === 'failed') {\n _this16._iceRestart(handleId);\n }\n\n _this16.emit('connectionState', [handleId, handleId === _this16.handleId, config.pc.connectionState]);\n\n if (handleId !== _this16.handleId && config.pc.connectionState === 'connected') {\n _this16.emit(_this16._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n stream: config.stream,\n track: null,\n optional: true,\n constructId: _this16.constructId,\n metaData: _this16.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 = function () {\n if (config.pc.iceConnectionState === 'failed') {\n _this16._iceRestart(handleId);\n }\n\n _this16.emit('iceState', [handleId, handleId === _this16.handleId, config.pc.iceConnectionState]);\n\n if (handleId !== _this16.handleId && (config.pc.iceConnectionState === 'completed' || config.pc.iceConnectionState === 'connected')) {\n _this16.emit(_this16._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n stream: config.stream,\n track: null,\n optional: true,\n constructId: _this16.constructId,\n metaData: _this16.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 = function (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 _this16._sendTrickleCandidate(handleId, {\n \"completed\": true\n }).catch(function (e) {\n _this16.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 _this16._sendTrickleCandidate(handleId, candidate).catch(function (e) {\n _this16.emit('error', e);\n });\n }\n };\n\n if (enableOntrack) {\n config.pc.ontrack = function (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 mid = event.transceiver ? event.transceiver.mid : event.track.id;\n config.stream.addTrack(event.track);\n\n _this16.emit(_this16._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n mid: mid,\n id: handle.handleId,\n userId: handle.userId,\n stream: config.stream,\n track: event.track,\n constructId: _this16.constructId,\n metaData: _this16.options.metaData,\n adding: true,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n\n if (event.track.onended) return;\n\n event.track.onended = function (ev) {\n var mid = ev.target.id;\n\n if (_this16.isUnifiedPlan) {\n var transceiver = config.pc.getTransceivers().find(function (t) {\n return t.receiver.track === ev.target;\n });\n mid = transceiver.mid;\n }\n\n if (config.stream) {\n config.stream && config.stream.removeTrack(ev.target);\n\n _this16.emit(_this16._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n mid: mid,\n userId: handle.userId,\n stream: config.stream,\n track: ev.target,\n constructId: _this16.constructId,\n metaData: _this16.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 = function (ev) {\n _this16._log('remoteTrackMuted', 'onmute');\n\n var mid = ev.target.id;\n\n if (_this16.isUnifiedPlan) {\n var transceiver = config.pc.getTransceivers().find(function (t) {\n return t.receiver.track === ev.target;\n });\n mid = transceiver.mid;\n }\n\n _this16.emit('remoteTrackMuted', {\n id: handle.handleId,\n mid: mid,\n userId: handle.userId,\n stream: config.stream,\n kind: ev.target.kind,\n track: ev.target,\n muted: true\n });\n };\n\n event.track.onunmute = function (ev) {\n _this16._log('remoteTrackMuted', 'onunmute');\n\n var mid = ev.target.id;\n\n if (_this16.isUnifiedPlan) {\n var transceiver = config.pc.getTransceivers().find(function (t) {\n return t.receiver.track === ev.target;\n });\n mid = transceiver.mid;\n }\n\n _this16.emit('remoteTrackMuted', {\n id: handle.handleId,\n mid: mid,\n userId: handle.userId,\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 = function onDataChannelMessage(event) {\n _this16._handleDataEvents(handleId, 'message', event.data);\n };\n\n var onDataChannelStateChange = function onDataChannelStateChange(event) {\n var label = event.target.label;\n var protocol = event.target.protocol;\n var state = config.dataChannel[label] ? config.dataChannel[label].readyState : \"null\";\n\n _this16._handleDataEvents(handleId, 'state', {\n state: state,\n label: label\n });\n }; //TODO: check this\n\n\n var onDataChannelError = function onDataChannelError(error) {\n var _error$channel;\n\n _this16._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: error\n });\n };\n\n var createDataChannel = function createDataChannel(label, protocol, incoming) {\n var options = {\n ordered: true\n };\n\n if (!incoming) {\n if (protocol) {\n options = _objectSpread(_objectSpread({}, options), {}, {\n protocol: 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 key: \"_webrtcPeer\",\n value: function _webrtcPeer(handleId, jsep) {\n var 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(function () {\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 key: \"_iceRestart\",\n value: function _iceRestart(handleId) {\n var _this17 = this;\n\n var 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 var hasAudio = !!(config.stream && config.stream.getAudioTracks().length > 0);\n var hasVideo = !!(config.stream && config.stream.getVideoTracks().length > 0);\n\n this._createAO('offer', handleId, true, [hasAudio, false, hasVideo, false]).then(function (jsep) {\n if (!jsep) {\n return null;\n }\n\n return _this17.sendMessage(handleId, {\n body: _objectSpread({\n \"request\": \"configure\",\n \"audio\": hasAudio,\n \"video\": hasVideo,\n \"data\": true\n }, _this17.recordingFilename ? {\n filename: _this17.recordingFilename\n } : {}),\n jsep: jsep\n });\n }).then(function (r) {\n config.isIceRestarting = false;\n\n _this17._log('ICE restart success');\n }).catch(function (e) {\n config.isIceRestarting = false;\n\n _this17.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(function () {\n config.isIceRestarting = false;\n }).catch(function () {\n config.isIceRestarting = false;\n });\n }\n }\n }, {\n key: \"_createAO\",\n value: function _createAO() {\n var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'offer';\n var handleId = arguments.length > 1 ? arguments[1] : undefined;\n var iceRestart = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n\n var _ref = arguments.length > 3 ? arguments[3] : undefined,\n _ref2 = _slicedToArray(_ref, 4),\n audioSend = _ref2[0],\n audioRecv = _ref2[1],\n videoSend = _ref2[2],\n videoRecv = _ref2[3];\n\n var 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 var 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 var _p = config.pc.setLocalDescription(response).catch(function (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(function () {\n return jsep;\n });\n }, function (e) {\n return Promise.reject({\n type: 'warning',\n id: 25,\n message: methodName,\n data: [handleId, e]\n });\n });\n }\n }, {\n key: \"_publishRemote\",\n value: function _publishRemote(handleId, jsep) {\n var _this18 = this;\n\n var 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 var config = handle.webrtcStuff;\n\n if (jsep) {\n return config.pc.setRemoteDescription(jsep).then(function () {\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 _this18._createAO('answer', handleId, false, [false, true, false, true]).then(function (_jsep) {\n if (!_jsep) {\n _this18.emit('error', {\n type: 'warning',\n id: 19,\n message: 'publish remote participant',\n data: [handleId, 'no jsep']\n });\n\n return Promise.resolve();\n }\n\n return _this18.sendMessage(handleId, {\n \"body\": _objectSpread(_objectSpread({\n \"request\": \"start\"\n }, _this18.roomId && {\n \"room\": _this18.roomId\n }), _this18.pin && {\n pin: _this18.pin\n }),\n \"jsep\": _jsep\n });\n });\n }, function (e) {\n return Promise.reject({\n type: 'warning',\n id: 23,\n message: 'setRemoteDescription',\n data: [handleId, e]\n });\n });\n } else {\n return Promise.resolve();\n }\n } //Public methods\n\n }, {\n key: \"publishLocal\",\n value: function publishLocal(stream) {\n var _this19 = this;\n\n var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n _ref3$keepAudio = _ref3.keepAudio,\n keepAudio = _ref3$keepAudio === void 0 ? false : _ref3$keepAudio,\n _ref3$keepVideo = _ref3.keepVideo,\n keepVideo = _ref3$keepVideo === void 0 ? false : _ref3$keepVideo;\n\n this.emit('publishing', true);\n\n var 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 var 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 var replaceAudio = stream.getAudioTracks().length;\n\n if (replaceAudio || !keepAudio) {\n //this will stop existing tracks\n var 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 (var index in config.pc.getSenders()) {\n var 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 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 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 var replaceVideo = stream.getVideoTracks().length;\n\n if (replaceVideo || !keepVideo) {\n var 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 (var _index in config.pc.getSenders()) {\n var _s2 = config.pc.getSenders()[_index];\n\n if (_s2 && _s2.track && _s2.track.kind === \"video\") {\n config.pc.removeTrack(_s2);\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 var _transceivers = config.pc.getTransceivers();\n\n if (_transceivers && _transceivers.length > 0) {\n for (var _i2 in _transceivers) {\n var _t = _transceivers[_i2];\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 var hasAudio = !!(stream && stream.getAudioTracks().length > 0);\n var hasVideo = !!(stream && stream.getVideoTracks().length > 0);\n var isAudioMuted = !stream || stream.getAudioTracks().length === 0 || !stream.getAudioTracks()[0].enabled;\n var 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(function (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 _this19.sendMessage(_this19.handleId, {\n body: _objectSpread({\n \"request\": \"configure\",\n \"audio\": hasAudio,\n \"video\": hasVideo,\n \"data\": true\n }, _this19.recordingFilename ? {\n filename: _this19.recordingFilename\n } : {}),\n jsep: jsep\n });\n }).then(function (r) {\n if (_this19._isDataChannelOpen) {\n return Promise.resolve(r);\n } else {\n return new Promise(function (resolve, reject) {\n var __ = function __(val) {\n if (val) {\n clearTimeout(_this19._dataChannelTimeoutId);\n\n _this19.off('dataChannel', __, _this19);\n\n resolve(_this19);\n }\n };\n\n _this19._dataChannelTimeoutId = setTimeout(function () {\n _this19.off('dataChannel', __, _this19);\n\n reject({\n type: 'error',\n id: 27,\n message: 'Data channel did not open',\n data: null\n });\n }, 5000);\n\n _this19.on('dataChannel', __, _this19);\n });\n }\n }).then(function (r) {\n _this19._isPublished = true;\n\n if (config.stream) {\n var tracks = config.stream.getTracks();\n tracks.forEach(function (track) {\n // used as a flag to not emit tracks that been already emitted\n if (!track.onended) {\n _this19.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n track: track,\n stream: config.stream,\n adding: true,\n constructId: _this19.constructId,\n metaData: _this19.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n\n track.onended = function (ev) {\n _this19.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n track: ev.target,\n stream: config.stream,\n adding: false,\n removing: true,\n constructId: _this19.constructId,\n metaData: _this19.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n };\n }\n });\n } else {\n _this19.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n stream: null,\n adding: false,\n constructId: _this19.constructId,\n metaData: _this19.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n }\n\n _this19.emit('published', {\n status: true,\n hasStream: !!config.stream\n });\n\n _this19.emit('publishing', false);\n\n _this19.emit('localHasVideo', hasVideo);\n\n _this19.emit('localHasAudio', hasAudio);\n\n _this19.emit('localMuted', {\n type: 'video',\n value: isVideoMuted\n });\n\n _this19.emit('localMuted', {\n type: 'audio',\n value: isAudioMuted\n });\n\n return r;\n }).catch(function (e) {\n _this19.emit('publishing', false);\n\n return Promise.reject(e);\n });\n }\n }, {\n key: \"unpublishLocal\",\n value: function unpublishLocal() {\n var _this20 = this;\n\n var 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(function (r) {\n _this20._isPublished = false;\n\n _this20.emit('published', {\n status: false,\n hasStream: false\n });\n\n return r;\n }) : Promise.resolve();\n }\n }, {\n key: \"toggleAudio\",\n value: function toggleAudio() {\n var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n var mid = arguments.length > 1 ? arguments[1] : undefined;\n\n var 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 var config = handle.webrtcStuff;\n\n if (this.isUnifiedPlan) {\n var transceiver = config.pc.getTransceivers().find(function (t) {\n return t.sender && t.sender.track && t.receiver.track.kind === \"audio\" && t.stopped === false && (mid ? t.mid === mid : true);\n });\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: mid\n });\n }\n }, {\n key: \"toggleVideo\",\n value: function toggleVideo() {\n var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n var mid = arguments.length > 1 ? arguments[1] : undefined;\n\n var 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 var config = handle.webrtcStuff;\n\n if (this.isUnifiedPlan) {\n var transceiver = config.pc.getTransceivers().find(function (t) {\n return t.sender && t.sender.track && t.receiver.track.kind === \"video\" && t.stopped === false && (mid ? t.mid === mid : true);\n });\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: mid\n });\n }\n }, {\n key: \"setInstructorId\",\n value: function setInstructorId() {\n var instructorId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n this._instuctorId = instructorId;\n this.emit('instructorId', this._instuctorId);\n return this._instuctorId;\n }\n }, {\n key: \"setObserverIds\",\n value: function setObserverIds() {\n var observerIds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n this._observerIds = observerIds;\n this.emit('observerIds', this._observerIds);\n return this._observerIds;\n }\n }, {\n key: \"setTalkbackIds\",\n value: function setTalkbackIds() {\n var talkbackIds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n this._talkbackIds = talkbackIds;\n this.emit('talkbackIds', this._talkbackIds);\n return this._talkbackIds;\n }\n }], [{\n key: \"noop\",\n value: function noop() {}\n }, {\n key: \"randomString\",\n value: function 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 key: \"checkUnifiedPlan\",\n value: function checkUnifiedPlan() {\n var 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 var 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\n return RoomSession;\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 watchTogether: ['participant', 'talkback'],\n videoWall: ['instructor', 'observer', 'talkback']\n },\n monitor: {\n watchTogether: ['participant'],\n videoWall: ['instructor', 'participant']\n },\n talkback: {\n watchTogether: ['participant'],\n videoWall: ['instructor', 'participant']\n },\n observer: {\n watchTogether: ['participant'],\n videoWall: ['participant']\n },\n instructor: {\n watchTogether: [],\n videoWall: []\n }\n});\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Room);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-room.js?");
9385
9385
 
9386
9386
  /***/ }),
9387
9387