@reactoo/watchtogether-sdk-js 2.4.19 → 2.4.20
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.
- package/dist/watchtogether-sdk.js +5 -5
- package/dist/watchtogether-sdk.min.js +2 -2
- package/package.json +1 -1
- package/src/modules/sync-modules/sync-dash-vod.js +1 -1
- package/src/modules/sync-modules/sync-hls-vod.js +1 -1
- package/src/modules/sync-modules/sync-native-hls-vod.js +1 -1
- package/src/modules/sync-modules/sync-shaka-dash-vod.js +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* @reactoo/watchtogether-sdk-js
|
|
3
|
-
* @version 2.4.
|
|
3
|
+
* @version 2.4.20
|
|
4
4
|
*/
|
|
5
5
|
(function webpackUniversalModuleDefinition(root, factory) {
|
|
6
6
|
if(typeof exports === 'object' && typeof module === 'object')
|
|
@@ -9727,7 +9727,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n\n\nfunction ownKeys(object,
|
|
|
9727
9727
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
9728
9728
|
|
|
9729
9729
|
"use strict";
|
|
9730
|
-
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); if (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 = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { 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({}, data), {}, {\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?");
|
|
9730
|
+
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); if (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 = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { 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?");
|
|
9731
9731
|
|
|
9732
9732
|
/***/ }),
|
|
9733
9733
|
|
|
@@ -9787,7 +9787,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
|
|
|
9787
9787
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
9788
9788
|
|
|
9789
9789
|
"use strict";
|
|
9790
|
-
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); if (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 = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { 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({}, data), {}, {\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?");
|
|
9790
|
+
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); if (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 = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { 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?");
|
|
9791
9791
|
|
|
9792
9792
|
/***/ }),
|
|
9793
9793
|
|
|
@@ -9811,7 +9811,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
|
|
|
9811
9811
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
9812
9812
|
|
|
9813
9813
|
"use strict";
|
|
9814
|
-
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); if (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 = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { 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({}, data), {}, {\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?");
|
|
9814
|
+
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); if (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 = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { 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?");
|
|
9815
9815
|
|
|
9816
9816
|
/***/ }),
|
|
9817
9817
|
|
|
@@ -9835,7 +9835,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
|
|
|
9835
9835
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
9836
9836
|
|
|
9837
9837
|
"use strict";
|
|
9838
|
-
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); if (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 = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { 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({}, data), {}, {\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?");
|
|
9838
|
+
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); if (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 = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { 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?");
|
|
9839
9839
|
|
|
9840
9840
|
/***/ }),
|
|
9841
9841
|
|