@reactoo/watchtogether-sdk-js 2.5.30 → 2.5.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @reactoo/watchtogether-sdk-js
3
- * @version 2.5.30
3
+ * @version 2.5.31
4
4
  */
5
5
  (function webpackUniversalModuleDefinition(root, factory) {
6
6
  if(typeof exports === 'object' && typeof module === 'object')
@@ -2636,7 +2636,7 @@ eval("var parent = __webpack_require__(/*! ../../actual/promise */ \"./node_modu
2636
2636
  /*! no static exports found */
2637
2637
  /***/ (function(module, exports, __webpack_require__) {
2638
2638
 
2639
- eval("var parent = __webpack_require__(/*! ../../actual/symbol */ \"./node_modules/core-js-pure/actual/symbol/index.js\");\n\n__webpack_require__(/*! ../../modules/esnext.symbol.async-dispose */ \"./node_modules/core-js-pure/modules/esnext.symbol.async-dispose.js\");\n\n__webpack_require__(/*! ../../modules/esnext.symbol.dispose */ \"./node_modules/core-js-pure/modules/esnext.symbol.dispose.js\");\n\n__webpack_require__(/*! ../../modules/esnext.symbol.matcher */ \"./node_modules/core-js-pure/modules/esnext.symbol.matcher.js\");\n\n__webpack_require__(/*! ../../modules/esnext.symbol.metadata */ \"./node_modules/core-js-pure/modules/esnext.symbol.metadata.js\");\n\n__webpack_require__(/*! ../../modules/esnext.symbol.observable */ \"./node_modules/core-js-pure/modules/esnext.symbol.observable.js\"); // TODO: Remove from `core-js@4`\n\n\n__webpack_require__(/*! ../../modules/esnext.symbol.pattern-match */ \"./node_modules/core-js-pure/modules/esnext.symbol.pattern-match.js\"); // TODO: Remove from `core-js@4`\n\n\n__webpack_require__(/*! ../../modules/esnext.symbol.replace-all */ \"./node_modules/core-js-pure/modules/esnext.symbol.replace-all.js\");\n\nmodule.exports = parent;\n\n//# sourceURL=webpack://WatchTogetherSDK/./node_modules/core-js-pure/full/symbol/index.js?");
2639
+ eval("var parent = __webpack_require__(/*! ../../actual/symbol */ \"./node_modules/core-js-pure/actual/symbol/index.js\");\n\n__webpack_require__(/*! ../../modules/esnext.symbol.async-dispose */ \"./node_modules/core-js-pure/modules/esnext.symbol.async-dispose.js\");\n\n__webpack_require__(/*! ../../modules/esnext.symbol.dispose */ \"./node_modules/core-js-pure/modules/esnext.symbol.dispose.js\");\n\n__webpack_require__(/*! ../../modules/esnext.symbol.matcher */ \"./node_modules/core-js-pure/modules/esnext.symbol.matcher.js\");\n\n__webpack_require__(/*! ../../modules/esnext.symbol.metadata-key */ \"./node_modules/core-js-pure/modules/esnext.symbol.metadata-key.js\");\n\n__webpack_require__(/*! ../../modules/esnext.symbol.observable */ \"./node_modules/core-js-pure/modules/esnext.symbol.observable.js\"); // TODO: Remove from `core-js@4`\n\n\n__webpack_require__(/*! ../../modules/esnext.symbol.metadata */ \"./node_modules/core-js-pure/modules/esnext.symbol.metadata.js\");\n\n__webpack_require__(/*! ../../modules/esnext.symbol.pattern-match */ \"./node_modules/core-js-pure/modules/esnext.symbol.pattern-match.js\");\n\n__webpack_require__(/*! ../../modules/esnext.symbol.replace-all */ \"./node_modules/core-js-pure/modules/esnext.symbol.replace-all.js\");\n\nmodule.exports = parent;\n\n//# sourceURL=webpack://WatchTogetherSDK/./node_modules/core-js-pure/full/symbol/index.js?");
2640
2640
 
2641
2641
  /***/ }),
2642
2642
 
@@ -4104,7 +4104,7 @@ eval("var global = __webpack_require__(/*! ../internals/global */ \"./node_modul
4104
4104
  /*! no static exports found */
4105
4105
  /***/ (function(module, exports, __webpack_require__) {
4106
4106
 
4107
- eval("var IS_PURE = __webpack_require__(/*! ../internals/is-pure */ \"./node_modules/core-js-pure/internals/is-pure.js\");\n\nvar store = __webpack_require__(/*! ../internals/shared-store */ \"./node_modules/core-js-pure/internals/shared-store.js\");\n\n(module.exports = function (key, value) {\n return store[key] || (store[key] = value !== undefined ? value : {});\n})('versions', []).push({\n version: '3.22.8',\n mode: IS_PURE ? 'pure' : 'global',\n copyright: '© 2014-2022 Denis Pushkarev (zloirock.ru)',\n license: 'https://github.com/zloirock/core-js/blob/v3.22.8/LICENSE',\n source: 'https://github.com/zloirock/core-js'\n});\n\n//# sourceURL=webpack://WatchTogetherSDK/./node_modules/core-js-pure/internals/shared.js?");
4107
+ eval("var IS_PURE = __webpack_require__(/*! ../internals/is-pure */ \"./node_modules/core-js-pure/internals/is-pure.js\");\n\nvar store = __webpack_require__(/*! ../internals/shared-store */ \"./node_modules/core-js-pure/internals/shared-store.js\");\n\n(module.exports = function (key, value) {\n return store[key] || (store[key] = value !== undefined ? value : {});\n})('versions', []).push({\n version: '3.23.3',\n mode: IS_PURE ? 'pure' : 'global',\n copyright: '© 2014-2022 Denis Pushkarev (zloirock.ru)',\n license: 'https://github.com/zloirock/core-js/blob/v3.23.3/LICENSE',\n source: 'https://github.com/zloirock/core-js'\n});\n\n//# sourceURL=webpack://WatchTogetherSDK/./node_modules/core-js-pure/internals/shared.js?");
4108
4108
 
4109
4109
  /***/ }),
4110
4110
 
@@ -5158,6 +5158,17 @@ eval("var defineWellKnownSymbol = __webpack_require__(/*! ../internals/define-we
5158
5158
 
5159
5159
  /***/ }),
5160
5160
 
5161
+ /***/ "./node_modules/core-js-pure/modules/esnext.symbol.metadata-key.js":
5162
+ /*!*************************************************************************!*\
5163
+ !*** ./node_modules/core-js-pure/modules/esnext.symbol.metadata-key.js ***!
5164
+ \*************************************************************************/
5165
+ /*! no static exports found */
5166
+ /***/ (function(module, exports, __webpack_require__) {
5167
+
5168
+ eval("var defineWellKnownSymbol = __webpack_require__(/*! ../internals/define-well-known-symbol */ \"./node_modules/core-js-pure/internals/define-well-known-symbol.js\"); // `Symbol.metadataKey` well-known symbol\n// https://github.com/tc39/proposal-decorator-metadata\n\n\ndefineWellKnownSymbol('metadataKey');\n\n//# sourceURL=webpack://WatchTogetherSDK/./node_modules/core-js-pure/modules/esnext.symbol.metadata-key.js?");
5169
+
5170
+ /***/ }),
5171
+
5161
5172
  /***/ "./node_modules/core-js-pure/modules/esnext.symbol.metadata.js":
5162
5173
  /*!*********************************************************************!*\
5163
5174
  !*** ./node_modules/core-js-pure/modules/esnext.symbol.metadata.js ***!
@@ -5165,7 +5176,7 @@ eval("var defineWellKnownSymbol = __webpack_require__(/*! ../internals/define-we
5165
5176
  /*! no static exports found */
5166
5177
  /***/ (function(module, exports, __webpack_require__) {
5167
5178
 
5168
- eval("var defineWellKnownSymbol = __webpack_require__(/*! ../internals/define-well-known-symbol */ \"./node_modules/core-js-pure/internals/define-well-known-symbol.js\"); // `Symbol.metadata` well-known symbol\n// https://github.com/tc39/proposal-decorators\n\n\ndefineWellKnownSymbol('metadata');\n\n//# sourceURL=webpack://WatchTogetherSDK/./node_modules/core-js-pure/modules/esnext.symbol.metadata.js?");
5179
+ eval("// TODO: Remove from `core-js@4`\nvar defineWellKnownSymbol = __webpack_require__(/*! ../internals/define-well-known-symbol */ \"./node_modules/core-js-pure/internals/define-well-known-symbol.js\"); // `Symbol.metadata` well-known symbol\n// https://github.com/tc39/proposal-decorators\n\n\ndefineWellKnownSymbol('metadata');\n\n//# sourceURL=webpack://WatchTogetherSDK/./node_modules/core-js-pure/modules/esnext.symbol.metadata.js?");
5169
5180
 
5170
5181
  /***/ }),
5171
5182
 
@@ -7724,7 +7735,7 @@ eval("\n\nvar utils = __webpack_require__(/*! ./utils */ \"./node_modules/qs/lib
7724
7735
  /***/ (function(module, exports, __webpack_require__) {
7725
7736
 
7726
7737
  "use strict";
7727
- eval("\n\nvar getSideChannel = __webpack_require__(/*! side-channel */ \"./node_modules/side-channel/index.js\");\n\nvar utils = __webpack_require__(/*! ./utils */ \"./node_modules/qs/lib/utils.js\");\n\nvar formats = __webpack_require__(/*! ./formats */ \"./node_modules/qs/lib/formats.js\");\n\nvar has = Object.prototype.hasOwnProperty;\nvar arrayPrefixGenerators = {\n brackets: function brackets(prefix) {\n return prefix + '[]';\n },\n comma: 'comma',\n indices: function indices(prefix, key) {\n return prefix + '[' + key + ']';\n },\n repeat: function repeat(prefix) {\n return prefix;\n }\n};\nvar isArray = Array.isArray;\nvar split = String.prototype.split;\nvar push = Array.prototype.push;\n\nvar pushToArray = function (arr, valueOrArray) {\n push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);\n};\n\nvar toISO = Date.prototype.toISOString;\nvar defaultFormat = formats['default'];\nvar defaults = {\n addQueryPrefix: false,\n allowDots: false,\n charset: 'utf-8',\n charsetSentinel: false,\n delimiter: '&',\n encode: true,\n encoder: utils.encode,\n encodeValuesOnly: false,\n format: defaultFormat,\n formatter: formats.formatters[defaultFormat],\n // deprecated\n indices: false,\n serializeDate: function serializeDate(date) {\n return toISO.call(date);\n },\n skipNulls: false,\n strictNullHandling: false\n};\n\nvar isNonNullishPrimitive = function isNonNullishPrimitive(v) {\n return typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean' || typeof v === 'symbol' || typeof v === 'bigint';\n};\n\nvar sentinel = {};\n\nvar stringify = function stringify(object, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots, serializeDate, format, formatter, encodeValuesOnly, charset, sideChannel) {\n var obj = object;\n var tmpSc = sideChannel;\n var step = 0;\n var findFlag = false;\n\n while ((tmpSc = tmpSc.get(sentinel)) !== void undefined && !findFlag) {\n // Where object last appeared in the ref tree\n var pos = tmpSc.get(object);\n step += 1;\n\n if (typeof pos !== 'undefined') {\n if (pos === step) {\n throw new RangeError('Cyclic object value');\n } else {\n findFlag = true; // Break while\n }\n }\n\n if (typeof tmpSc.get(sentinel) === 'undefined') {\n step = 0;\n }\n }\n\n if (typeof filter === 'function') {\n obj = filter(prefix, obj);\n } else if (obj instanceof Date) {\n obj = serializeDate(obj);\n } else if (generateArrayPrefix === 'comma' && isArray(obj)) {\n obj = utils.maybeMap(obj, function (value) {\n if (value instanceof Date) {\n return serializeDate(value);\n }\n\n return value;\n });\n }\n\n if (obj === null) {\n if (strictNullHandling) {\n return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset, 'key', format) : prefix;\n }\n\n obj = '';\n }\n\n if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {\n if (encoder) {\n var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key', format);\n\n if (generateArrayPrefix === 'comma' && encodeValuesOnly) {\n var valuesArray = split.call(String(obj), ',');\n var valuesJoined = '';\n\n for (var i = 0; i < valuesArray.length; ++i) {\n valuesJoined += (i === 0 ? '' : ',') + formatter(encoder(valuesArray[i], defaults.encoder, charset, 'value', format));\n }\n\n return [formatter(keyValue) + (isArray(obj) && valuesArray.length === 1 ? '[]' : '') + '=' + valuesJoined];\n }\n\n return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value', format))];\n }\n\n return [formatter(prefix) + '=' + formatter(String(obj))];\n }\n\n var values = [];\n\n if (typeof obj === 'undefined') {\n return values;\n }\n\n var objKeys;\n\n if (generateArrayPrefix === 'comma' && isArray(obj)) {\n // we need to join elements in\n objKeys = [{\n value: obj.length > 0 ? obj.join(',') || null : void undefined\n }];\n } else if (isArray(filter)) {\n objKeys = filter;\n } else {\n var keys = Object.keys(obj);\n objKeys = sort ? keys.sort(sort) : keys;\n }\n\n var adjustedPrefix = generateArrayPrefix === 'comma' && isArray(obj) && obj.length === 1 ? prefix + '[]' : prefix;\n\n for (var j = 0; j < objKeys.length; ++j) {\n var key = objKeys[j];\n var value = typeof key === 'object' && typeof key.value !== 'undefined' ? key.value : obj[key];\n\n if (skipNulls && value === null) {\n continue;\n }\n\n var keyPrefix = isArray(obj) ? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(adjustedPrefix, key) : adjustedPrefix : adjustedPrefix + (allowDots ? '.' + key : '[' + key + ']');\n sideChannel.set(object, step);\n var valueSideChannel = getSideChannel();\n valueSideChannel.set(sentinel, sideChannel);\n pushToArray(values, stringify(value, keyPrefix, generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots, serializeDate, format, formatter, encodeValuesOnly, charset, valueSideChannel));\n }\n\n return values;\n};\n\nvar normalizeStringifyOptions = function normalizeStringifyOptions(opts) {\n if (!opts) {\n return defaults;\n }\n\n if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') {\n throw new TypeError('Encoder has to be a function.');\n }\n\n var charset = opts.charset || defaults.charset;\n\n if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') {\n throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined');\n }\n\n var format = formats['default'];\n\n if (typeof opts.format !== 'undefined') {\n if (!has.call(formats.formatters, opts.format)) {\n throw new TypeError('Unknown format option provided.');\n }\n\n format = opts.format;\n }\n\n var formatter = formats.formatters[format];\n var filter = defaults.filter;\n\n if (typeof opts.filter === 'function' || isArray(opts.filter)) {\n filter = opts.filter;\n }\n\n return {\n addQueryPrefix: typeof opts.addQueryPrefix === 'boolean' ? opts.addQueryPrefix : defaults.addQueryPrefix,\n allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots,\n charset: charset,\n charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel,\n delimiter: typeof opts.delimiter === 'undefined' ? defaults.delimiter : opts.delimiter,\n encode: typeof opts.encode === 'boolean' ? opts.encode : defaults.encode,\n encoder: typeof opts.encoder === 'function' ? opts.encoder : defaults.encoder,\n encodeValuesOnly: typeof opts.encodeValuesOnly === 'boolean' ? opts.encodeValuesOnly : defaults.encodeValuesOnly,\n filter: filter,\n format: format,\n formatter: formatter,\n serializeDate: typeof opts.serializeDate === 'function' ? opts.serializeDate : defaults.serializeDate,\n skipNulls: typeof opts.skipNulls === 'boolean' ? opts.skipNulls : defaults.skipNulls,\n sort: typeof opts.sort === 'function' ? opts.sort : null,\n strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling\n };\n};\n\nmodule.exports = function (object, opts) {\n var obj = object;\n var options = normalizeStringifyOptions(opts);\n var objKeys;\n var filter;\n\n if (typeof options.filter === 'function') {\n filter = options.filter;\n obj = filter('', obj);\n } else if (isArray(options.filter)) {\n filter = options.filter;\n objKeys = filter;\n }\n\n var keys = [];\n\n if (typeof obj !== 'object' || obj === null) {\n return '';\n }\n\n var arrayFormat;\n\n if (opts && opts.arrayFormat in arrayPrefixGenerators) {\n arrayFormat = opts.arrayFormat;\n } else if (opts && 'indices' in opts) {\n arrayFormat = opts.indices ? 'indices' : 'repeat';\n } else {\n arrayFormat = 'indices';\n }\n\n var generateArrayPrefix = arrayPrefixGenerators[arrayFormat];\n\n if (!objKeys) {\n objKeys = Object.keys(obj);\n }\n\n if (options.sort) {\n objKeys.sort(options.sort);\n }\n\n var sideChannel = getSideChannel();\n\n for (var i = 0; i < objKeys.length; ++i) {\n var key = objKeys[i];\n\n if (options.skipNulls && obj[key] === null) {\n continue;\n }\n\n pushToArray(keys, stringify(obj[key], key, generateArrayPrefix, options.strictNullHandling, options.skipNulls, options.encode ? options.encoder : null, options.filter, options.sort, options.allowDots, options.serializeDate, options.format, options.formatter, options.encodeValuesOnly, options.charset, sideChannel));\n }\n\n var joined = keys.join(options.delimiter);\n var prefix = options.addQueryPrefix === true ? '?' : '';\n\n if (options.charsetSentinel) {\n if (options.charset === 'iso-8859-1') {\n // encodeURIComponent('&#10003;'), the \"numeric entity\" representation of a checkmark\n prefix += 'utf8=%26%2310003%3B&';\n } else {\n // encodeURIComponent('✓')\n prefix += 'utf8=%E2%9C%93&';\n }\n }\n\n return joined.length > 0 ? prefix + joined : '';\n};\n\n//# sourceURL=webpack://WatchTogetherSDK/./node_modules/qs/lib/stringify.js?");
7738
+ eval("\n\nvar getSideChannel = __webpack_require__(/*! side-channel */ \"./node_modules/side-channel/index.js\");\n\nvar utils = __webpack_require__(/*! ./utils */ \"./node_modules/qs/lib/utils.js\");\n\nvar formats = __webpack_require__(/*! ./formats */ \"./node_modules/qs/lib/formats.js\");\n\nvar has = Object.prototype.hasOwnProperty;\nvar arrayPrefixGenerators = {\n brackets: function brackets(prefix) {\n return prefix + '[]';\n },\n comma: 'comma',\n indices: function indices(prefix, key) {\n return prefix + '[' + key + ']';\n },\n repeat: function repeat(prefix) {\n return prefix;\n }\n};\nvar isArray = Array.isArray;\nvar split = String.prototype.split;\nvar push = Array.prototype.push;\n\nvar pushToArray = function (arr, valueOrArray) {\n push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);\n};\n\nvar toISO = Date.prototype.toISOString;\nvar defaultFormat = formats['default'];\nvar defaults = {\n addQueryPrefix: false,\n allowDots: false,\n charset: 'utf-8',\n charsetSentinel: false,\n delimiter: '&',\n encode: true,\n encoder: utils.encode,\n encodeValuesOnly: false,\n format: defaultFormat,\n formatter: formats.formatters[defaultFormat],\n // deprecated\n indices: false,\n serializeDate: function serializeDate(date) {\n return toISO.call(date);\n },\n skipNulls: false,\n strictNullHandling: false\n};\n\nvar isNonNullishPrimitive = function isNonNullishPrimitive(v) {\n return typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean' || typeof v === 'symbol' || typeof v === 'bigint';\n};\n\nvar sentinel = {};\n\nvar stringify = function stringify(object, prefix, generateArrayPrefix, commaRoundTrip, strictNullHandling, skipNulls, encoder, filter, sort, allowDots, serializeDate, format, formatter, encodeValuesOnly, charset, sideChannel) {\n var obj = object;\n var tmpSc = sideChannel;\n var step = 0;\n var findFlag = false;\n\n while ((tmpSc = tmpSc.get(sentinel)) !== void undefined && !findFlag) {\n // Where object last appeared in the ref tree\n var pos = tmpSc.get(object);\n step += 1;\n\n if (typeof pos !== 'undefined') {\n if (pos === step) {\n throw new RangeError('Cyclic object value');\n } else {\n findFlag = true; // Break while\n }\n }\n\n if (typeof tmpSc.get(sentinel) === 'undefined') {\n step = 0;\n }\n }\n\n if (typeof filter === 'function') {\n obj = filter(prefix, obj);\n } else if (obj instanceof Date) {\n obj = serializeDate(obj);\n } else if (generateArrayPrefix === 'comma' && isArray(obj)) {\n obj = utils.maybeMap(obj, function (value) {\n if (value instanceof Date) {\n return serializeDate(value);\n }\n\n return value;\n });\n }\n\n if (obj === null) {\n if (strictNullHandling) {\n return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset, 'key', format) : prefix;\n }\n\n obj = '';\n }\n\n if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {\n if (encoder) {\n var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key', format);\n\n if (generateArrayPrefix === 'comma' && encodeValuesOnly) {\n var valuesArray = split.call(String(obj), ',');\n var valuesJoined = '';\n\n for (var i = 0; i < valuesArray.length; ++i) {\n valuesJoined += (i === 0 ? '' : ',') + formatter(encoder(valuesArray[i], defaults.encoder, charset, 'value', format));\n }\n\n return [formatter(keyValue) + (commaRoundTrip && isArray(obj) && valuesArray.length === 1 ? '[]' : '') + '=' + valuesJoined];\n }\n\n return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value', format))];\n }\n\n return [formatter(prefix) + '=' + formatter(String(obj))];\n }\n\n var values = [];\n\n if (typeof obj === 'undefined') {\n return values;\n }\n\n var objKeys;\n\n if (generateArrayPrefix === 'comma' && isArray(obj)) {\n // we need to join elements in\n objKeys = [{\n value: obj.length > 0 ? obj.join(',') || null : void undefined\n }];\n } else if (isArray(filter)) {\n objKeys = filter;\n } else {\n var keys = Object.keys(obj);\n objKeys = sort ? keys.sort(sort) : keys;\n }\n\n var adjustedPrefix = commaRoundTrip && isArray(obj) && obj.length === 1 ? prefix + '[]' : prefix;\n\n for (var j = 0; j < objKeys.length; ++j) {\n var key = objKeys[j];\n var value = typeof key === 'object' && typeof key.value !== 'undefined' ? key.value : obj[key];\n\n if (skipNulls && value === null) {\n continue;\n }\n\n var keyPrefix = isArray(obj) ? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(adjustedPrefix, key) : adjustedPrefix : adjustedPrefix + (allowDots ? '.' + key : '[' + key + ']');\n sideChannel.set(object, step);\n var valueSideChannel = getSideChannel();\n valueSideChannel.set(sentinel, sideChannel);\n pushToArray(values, stringify(value, keyPrefix, generateArrayPrefix, commaRoundTrip, strictNullHandling, skipNulls, encoder, filter, sort, allowDots, serializeDate, format, formatter, encodeValuesOnly, charset, valueSideChannel));\n }\n\n return values;\n};\n\nvar normalizeStringifyOptions = function normalizeStringifyOptions(opts) {\n if (!opts) {\n return defaults;\n }\n\n if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') {\n throw new TypeError('Encoder has to be a function.');\n }\n\n var charset = opts.charset || defaults.charset;\n\n if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') {\n throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined');\n }\n\n var format = formats['default'];\n\n if (typeof opts.format !== 'undefined') {\n if (!has.call(formats.formatters, opts.format)) {\n throw new TypeError('Unknown format option provided.');\n }\n\n format = opts.format;\n }\n\n var formatter = formats.formatters[format];\n var filter = defaults.filter;\n\n if (typeof opts.filter === 'function' || isArray(opts.filter)) {\n filter = opts.filter;\n }\n\n return {\n addQueryPrefix: typeof opts.addQueryPrefix === 'boolean' ? opts.addQueryPrefix : defaults.addQueryPrefix,\n allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots,\n charset: charset,\n charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel,\n delimiter: typeof opts.delimiter === 'undefined' ? defaults.delimiter : opts.delimiter,\n encode: typeof opts.encode === 'boolean' ? opts.encode : defaults.encode,\n encoder: typeof opts.encoder === 'function' ? opts.encoder : defaults.encoder,\n encodeValuesOnly: typeof opts.encodeValuesOnly === 'boolean' ? opts.encodeValuesOnly : defaults.encodeValuesOnly,\n filter: filter,\n format: format,\n formatter: formatter,\n serializeDate: typeof opts.serializeDate === 'function' ? opts.serializeDate : defaults.serializeDate,\n skipNulls: typeof opts.skipNulls === 'boolean' ? opts.skipNulls : defaults.skipNulls,\n sort: typeof opts.sort === 'function' ? opts.sort : null,\n strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling\n };\n};\n\nmodule.exports = function (object, opts) {\n var obj = object;\n var options = normalizeStringifyOptions(opts);\n var objKeys;\n var filter;\n\n if (typeof options.filter === 'function') {\n filter = options.filter;\n obj = filter('', obj);\n } else if (isArray(options.filter)) {\n filter = options.filter;\n objKeys = filter;\n }\n\n var keys = [];\n\n if (typeof obj !== 'object' || obj === null) {\n return '';\n }\n\n var arrayFormat;\n\n if (opts && opts.arrayFormat in arrayPrefixGenerators) {\n arrayFormat = opts.arrayFormat;\n } else if (opts && 'indices' in opts) {\n arrayFormat = opts.indices ? 'indices' : 'repeat';\n } else {\n arrayFormat = 'indices';\n }\n\n var generateArrayPrefix = arrayPrefixGenerators[arrayFormat];\n\n if (opts && 'commaRoundTrip' in opts && typeof opts.commaRoundTrip !== 'boolean') {\n throw new TypeError('`commaRoundTrip` must be a boolean, or absent');\n }\n\n var commaRoundTrip = generateArrayPrefix === 'comma' && opts && opts.commaRoundTrip;\n\n if (!objKeys) {\n objKeys = Object.keys(obj);\n }\n\n if (options.sort) {\n objKeys.sort(options.sort);\n }\n\n var sideChannel = getSideChannel();\n\n for (var i = 0; i < objKeys.length; ++i) {\n var key = objKeys[i];\n\n if (options.skipNulls && obj[key] === null) {\n continue;\n }\n\n pushToArray(keys, stringify(obj[key], key, generateArrayPrefix, commaRoundTrip, options.strictNullHandling, options.skipNulls, options.encode ? options.encoder : null, options.filter, options.sort, options.allowDots, options.serializeDate, options.format, options.formatter, options.encodeValuesOnly, options.charset, sideChannel));\n }\n\n var joined = keys.join(options.delimiter);\n var prefix = options.addQueryPrefix === true ? '?' : '';\n\n if (options.charsetSentinel) {\n if (options.charset === 'iso-8859-1') {\n // encodeURIComponent('&#10003;'), the \"numeric entity\" representation of a checkmark\n prefix += 'utf8=%26%2310003%3B&';\n } else {\n // encodeURIComponent('✓')\n prefix += 'utf8=%E2%9C%93&';\n }\n }\n\n return joined.length > 0 ? prefix + joined : '';\n};\n\n//# sourceURL=webpack://WatchTogetherSDK/./node_modules/qs/lib/stringify.js?");
7728
7739
 
7729
7740
  /***/ }),
7730
7741
 
@@ -9069,7 +9080,7 @@ eval("module.exports = extend;\nvar hasOwnProperty = Object.prototype.hasOwnProp
9069
9080
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9070
9081
 
9071
9082
  "use strict";
9072
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _modules_wt_room__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./modules/wt-room */ \"./src/modules/wt-room.js\");\n/* harmony import */ var _modules_wt_auth__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modules/wt-auth */ \"./src/modules/wt-auth.js\");\n/* harmony import */ var _modules_wt_iot__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./modules/wt-iot */ \"./src/modules/wt-iot.js\");\n/* harmony import */ var _models_auth__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./models/auth */ \"./src/models/auth.js\");\n/* harmony import */ var _models_room__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./models/room */ \"./src/models/room.js\");\n/* harmony import */ var _models_user__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./models/user */ \"./src/models/user.js\");\n/* harmony import */ var _models_asset__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./models/asset */ \"./src/models/asset.js\");\n/* harmony import */ var _models_system__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./models/system */ \"./src/models/system.js\");\n/* harmony import */ var _models_utils__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./models/utils */ \"./src/models/utils.js\");\n/* harmony import */ var _models_iot__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./models/iot */ \"./src/models/iot.js\");\n\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n\n\n\n\n\n\n\n\n\n\n\nfunction WatchTogether() {\n var _this = this;\n\n var modules = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var instanceType = arguments.length > 1 ? arguments[1] : undefined;\n var debug = arguments.length > 2 ? arguments[2] : undefined;\n var playerFactory = arguments.length > 3 ? arguments[3] : undefined;\n var providerAuth = arguments.length > 4 ? arguments[4] : undefined;\n this.username = null;\n this.userId = null;\n this.__instanceType = instanceType;\n this.__debug = debug;\n this.__privates = {\n playerFactory: playerFactory,\n providerAuth: providerAuth,\n room: modules.room,\n auth: modules.auth,\n iot: modules.iot\n };\n\n this.setInstanceType = function (newInstanceType) {\n return _this.__instanceType = newInstanceType;\n };\n\n this.isReady = modules.room.whenInitialized;\n this.browser = modules.room.browser;\n this.browserDetails = modules.room.browserDetails;\n this.auth = _objectSpread({}, _models_auth__WEBPACK_IMPORTED_MODULE_3__[\"default\"].call(this));\n this.user = _objectSpread({}, _models_user__WEBPACK_IMPORTED_MODULE_5__[\"default\"].call(this));\n this.room = _objectSpread({}, _models_room__WEBPACK_IMPORTED_MODULE_4__[\"default\"].call(this));\n this.asset = _objectSpread({}, _models_asset__WEBPACK_IMPORTED_MODULE_6__[\"default\"].call(this));\n this.system = _objectSpread({}, _models_system__WEBPACK_IMPORTED_MODULE_7__[\"default\"].call(this));\n this.iot = _objectSpread({}, _models_iot__WEBPACK_IMPORTED_MODULE_9__[\"default\"].call(this));\n this.utils = _models_utils__WEBPACK_IMPORTED_MODULE_8__[\"default\"];\n}\n\nvar watchTogether = function watchTogether() {\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref$debug = _ref.debug,\n debug = _ref$debug === void 0 ? true : _ref$debug,\n _ref$language = _ref.language,\n language = _ref$language === void 0 ? 'en-GB' : _ref$language,\n _ref$storagePrefix = _ref.storagePrefix,\n storagePrefix = _ref$storagePrefix === void 0 ? \"reactoo_\" : _ref$storagePrefix,\n _ref$apiUrl = _ref.apiUrl,\n apiUrl = _ref$apiUrl === void 0 ? null : _ref$apiUrl;\n\n var room = new _modules_wt_room__WEBPACK_IMPORTED_MODULE_0__[\"default\"](debug);\n var auth = new _modules_wt_auth__WEBPACK_IMPORTED_MODULE_1__[\"default\"](debug, language, storagePrefix, apiUrl);\n var iot = new _modules_wt_iot__WEBPACK_IMPORTED_MODULE_2__[\"default\"](debug);\n return function () {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref2$instanceType = _ref2.instanceType,\n instanceType = _ref2$instanceType === void 0 ? 'reactooDemo' : _ref2$instanceType,\n _ref2$playerFactory = _ref2.playerFactory,\n playerFactory = _ref2$playerFactory === void 0 ? null : _ref2$playerFactory,\n _ref2$providerAuth = _ref2.providerAuth,\n providerAuth = _ref2$providerAuth === void 0 ? null : _ref2$providerAuth;\n\n return new WatchTogether({\n room: room,\n auth: auth,\n iot: iot\n }, instanceType, debug, playerFactory, providerAuth);\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (watchTogether);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/index.js?");
9083
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _modules_wt_room__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./modules/wt-room */ \"./src/modules/wt-room.js\");\n/* harmony import */ var _modules_wt_auth__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modules/wt-auth */ \"./src/modules/wt-auth.js\");\n/* harmony import */ var _modules_wt_iot__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./modules/wt-iot */ \"./src/modules/wt-iot.js\");\n/* harmony import */ var _models_auth__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./models/auth */ \"./src/models/auth.js\");\n/* harmony import */ var _models_room__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./models/room */ \"./src/models/room.js\");\n/* harmony import */ var _models_user__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./models/user */ \"./src/models/user.js\");\n/* harmony import */ var _models_asset__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./models/asset */ \"./src/models/asset.js\");\n/* harmony import */ var _models_system__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./models/system */ \"./src/models/system.js\");\n/* harmony import */ var _models_utils__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./models/utils */ \"./src/models/utils.js\");\n/* harmony import */ var _models_iot__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./models/iot */ \"./src/models/iot.js\");\n\n\n\n\n\n\n\n\n\n\n\n\n\nfunction WatchTogether() {\n let modules = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let instanceType = arguments.length > 1 ? arguments[1] : undefined;\n let debug = arguments.length > 2 ? arguments[2] : undefined;\n let playerFactory = arguments.length > 3 ? arguments[3] : undefined;\n let providerAuth = arguments.length > 4 ? arguments[4] : undefined;\n this.username = null;\n this.userId = null;\n this.__instanceType = instanceType;\n this.__debug = debug;\n this.__privates = {\n playerFactory,\n providerAuth,\n room: modules.room,\n auth: modules.auth,\n iot: modules.iot\n };\n\n this.setInstanceType = newInstanceType => this.__instanceType = newInstanceType;\n\n this.isReady = modules.room.whenInitialized;\n this.browser = modules.room.browser;\n this.browserDetails = modules.room.browserDetails;\n this.auth = { ..._models_auth__WEBPACK_IMPORTED_MODULE_3__[\"default\"].call(this)\n };\n this.user = { ..._models_user__WEBPACK_IMPORTED_MODULE_5__[\"default\"].call(this)\n };\n this.room = { ..._models_room__WEBPACK_IMPORTED_MODULE_4__[\"default\"].call(this)\n };\n this.asset = { ..._models_asset__WEBPACK_IMPORTED_MODULE_6__[\"default\"].call(this)\n };\n this.system = { ..._models_system__WEBPACK_IMPORTED_MODULE_7__[\"default\"].call(this)\n };\n this.iot = { ..._models_iot__WEBPACK_IMPORTED_MODULE_9__[\"default\"].call(this)\n };\n this.utils = _models_utils__WEBPACK_IMPORTED_MODULE_8__[\"default\"];\n}\n\nlet watchTogether = function () {\n let {\n debug = true,\n language = 'en-GB',\n storagePrefix = \"reactoo_\",\n apiUrl = null\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let room = new _modules_wt_room__WEBPACK_IMPORTED_MODULE_0__[\"default\"](debug);\n let auth = new _modules_wt_auth__WEBPACK_IMPORTED_MODULE_1__[\"default\"](debug, language, storagePrefix, apiUrl);\n let iot = new _modules_wt_iot__WEBPACK_IMPORTED_MODULE_2__[\"default\"](debug);\n return function () {\n let {\n instanceType = 'reactooDemo',\n playerFactory = null,\n providerAuth = null\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return new WatchTogether({\n room,\n auth,\n iot\n }, instanceType, debug, playerFactory, providerAuth);\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (watchTogether);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/index.js?");
9073
9084
 
9074
9085
  /***/ }),
9075
9086
 
@@ -9081,7 +9092,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _mod
9081
9092
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9082
9093
 
9083
9094
  "use strict";
9084
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\nfunction _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n\n\nvar asset = function asset() {\n var _this = this;\n\n return {\n getAssetList: function getAssetList(_ref) {\n var _ref$type = _ref.type,\n type = _ref$type === void 0 ? 'instanceType' : _ref$type,\n instanceType = _ref.instanceType,\n _ref$size = _ref.size,\n size = _ref$size === void 0 ? 20 : _ref$size,\n _ref$startKey = _ref.startKey,\n startKey = _ref$startKey === void 0 ? null : _ref$startKey,\n roomId = _ref.roomId;\n\n var apiParams = _objectSpread(_objectSpread(_objectSpread({}, instanceType && {\n instanceType: instanceType === true ? _this.__instanceType : instanceType\n }), {}, {\n type: type,\n size: size\n }, roomId && {\n roomId: roomId\n }), startKey && {\n startKey: startKey\n });\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.asset.getAssetList(apiParams);\n });\n },\n updateAsset: function updateAsset() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n id = _ref2.id,\n assetType = _ref2.assetType,\n title = _ref2.title,\n roomIds = _ref2.roomIds;\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.asset.updateAsset({\n id: id\n }, {\n requestBody: {\n assetType: assetType,\n title: title,\n roomIds: roomIds\n }\n });\n });\n },\n deleteAsset: function deleteAsset(id) {\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.asset.deleteAsset({\n id: id\n });\n });\n },\n uploadAsset: function uploadAsset(file, roomIds) {\n var id = Object(_modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"generateUUID\"])();\n return _this.__privates.auth.__client.then(function (client) {\n return Promise.all([client, client.apis.asset.initiateAssetUpload({\n id: id\n })]);\n }).then(function (_ref3) {\n var _ref4 = _slicedToArray(_ref3, 2),\n client = _ref4[0],\n response = _ref4[1];\n\n return Promise.all([client, client.http({\n url: response.data.signedUrl,\n method: response.data.httpMethod,\n headers: {\n \"Content-Type\": file.type\n },\n body: file\n }), response.data.id]);\n }).then(function (_ref5) {\n var _ref6 = _slicedToArray(_ref5, 3),\n client = _ref6[0],\n response = _ref6[1],\n idn = _ref6[2];\n\n return client.apis.asset.publishAsset({\n id: idn\n }, {\n requestBody: _objectSpread({\n title: file.name\n }, roomIds ? {\n roomIds: roomIds\n } : {})\n });\n });\n },\n downloadAsset: function downloadAsset(url) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n return _this.__privates.auth.__client.then(function (client) {\n return client.http(_objectSpread({\n url: url,\n method: 'GET'\n }, options));\n });\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (asset);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/asset.js?");
9095
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/wt-utils */ \"./src/modules/wt-utils.js\");\n\n\n\n\nlet asset = function () {\n var _this = this;\n\n return {\n getAssetList: _ref => {\n let {\n type = 'instanceType',\n instanceType,\n size = 20,\n startKey = null,\n roomId\n } = _ref;\n let apiParams = { ...(instanceType && {\n instanceType: instanceType === true ? this.__instanceType : instanceType\n }),\n type,\n size,\n ...(roomId && {\n roomId\n }),\n ...(startKey && {\n startKey\n })\n };\n return this.__privates.auth.__client.then(client => client.apis.asset.getAssetList(apiParams));\n },\n updateAsset: function () {\n let {\n id,\n assetType,\n title,\n roomIds\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.asset.updateAsset({\n id\n }, {\n requestBody: {\n assetType,\n title,\n roomIds\n }\n }));\n },\n deleteAsset: id => {\n return this.__privates.auth.__client.then(client => client.apis.asset.deleteAsset({\n id\n }));\n },\n uploadAsset: (file, roomIds) => {\n let id = Object(_modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"generateUUID\"])();\n return this.__privates.auth.__client.then(client => Promise.all([client, client.apis.asset.initiateAssetUpload({\n id\n })])).then(_ref2 => {\n let [client, response] = _ref2;\n return Promise.all([client, client.http({\n url: response.data.signedUrl,\n method: response.data.httpMethod,\n headers: {\n \"Content-Type\": file.type\n },\n body: file\n }), response.data.id]);\n }).then(_ref3 => {\n let [client, response, idn] = _ref3;\n return client.apis.asset.publishAsset({\n id: idn\n }, {\n requestBody: {\n title: file.name,\n ...(roomIds ? {\n roomIds\n } : {})\n }\n });\n });\n },\n downloadAsset: function (url) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n return _this.__privates.auth.__client.then(client => client.http({\n url,\n method: 'GET',\n ...options\n }));\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (asset);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/asset.js?");
9085
9096
 
9086
9097
  /***/ }),
9087
9098
 
@@ -9093,7 +9104,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _mod
9093
9104
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9094
9105
 
9095
9106
  "use strict";
9096
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\nfunction _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n\n\nvar auth = function auth() {\n var _this = this;\n\n return {\n login: function login(username, password) {\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.auth.signIn({}, {\n requestBody: {\n username: username,\n password: password\n }\n });\n }).then(function (response) {\n _this.userId = response.data.userId;\n _this.username = response.data.username;\n return _this.__privates.auth.login(response.data.idToken, response.data.accessToken, response.data.refreshToken);\n });\n },\n providerLogin: function providerLogin(domain, token, displayname, deviceId) {\n if (!token && typeof _this.__privates.providerAuth === 'function') {\n var _this$__privates$prov = _this.__privates.providerAuth();\n\n token = _this$__privates$prov.token;\n displayname = _this$__privates$prov.displayname;\n }\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.auth.providerSignIn({}, {\n requestBody: _objectSpread(_objectSpread({\n domain: domain,\n token: token\n }, displayname && {\n displayname: displayname\n }), deviceId && {\n deviceId: deviceId\n })\n });\n }).then(function (response) {\n _this.userId = response.data.userId;\n _this.username = response.data.username;\n return _this.__privates.auth.login(response.data.idToken, response.data.accessToken, response.data.refreshToken);\n });\n },\n getProviderAuth: function getProviderAuth() {\n return _this.__privates.providerAuth;\n },\n deviceLogin: function deviceLogin(salt) {\n return Object(_modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"getBrowserFingerprint\"])(_this.__instanceType, salt).then(function (deviceId) {\n return Promise.all([deviceId, _this.__privates.auth.__client]);\n }).then(function (_ref) {\n var _ref2 = _slicedToArray(_ref, 2),\n deviceId = _ref2[0],\n client = _ref2[1];\n\n return client.apis.auth.deviceSignIn({}, {\n requestBody: {\n deviceId: deviceId,\n domain: location.hostname\n }\n });\n }).then(function (response) {\n _this.userId = response.data.userId;\n _this.username = response.data.username;\n return _this.__privates.auth.login(response.data.idToken, response.data.accessToken, response.data.refreshToken);\n });\n },\n logout: function logout() {\n return _this.__privates.auth.logout();\n },\n isLoggedIn: function isLoggedIn() {\n return _this.__privates.auth.isLoggedIn();\n },\n setLanguage: function setLanguage(language) {\n return _this.__privates.auth.setLanguage(language);\n },\n getLanguage: function getLanguage() {\n return _this.__privates.auth.__language;\n },\n signUp: function signUp(username, password, email, phone) {\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.auth.signUp({}, {\n requestBody: {\n username: username,\n password: password,\n email: email,\n phone: phone\n }\n });\n });\n },\n confirmSignUp: function confirmSignUp(confirmationCode, username, displayname) {\n var isPublic = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.auth.confirmSignUp({}, {\n requestBody: {\n confirmationCode: confirmationCode,\n username: username,\n displayname: displayname,\n isPublic: isPublic\n }\n });\n }).then(function (response) {\n _this.userId = response.data.userId;\n _this.username = response.data.username;\n return _this.__privates.auth.login(response.data.idToken, response.data.accessToken, response.data.refreshToken);\n });\n },\n resendConfirmationCode: function resendConfirmationCode(username) {\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.auth.resendConfirmationCode({}, {\n requestBody: {\n username: username\n }\n });\n });\n },\n forgotPassword: function forgotPassword(username) {\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.auth.forgotPassword({}, {\n requestBody: {\n username: username\n }\n });\n });\n },\n confirmForgotPassword: function confirmForgotPassword(username, confirmationCode, password) {\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.auth.confirmForgotPassword({}, {\n requestBody: {\n password: password,\n confirmationCode: confirmationCode,\n username: username\n }\n });\n });\n },\n $on: function $on(key, callback, that) {\n return _this.__privates.auth.on(key, callback, that || _this);\n },\n $off: function $off(key, callback, that) {\n return _this.__privates.auth.off(key, callback, that || _this);\n },\n $clear: function $clear() {\n return _this.__privates.auth.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (auth);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/auth.js?");
9107
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/wt-utils */ \"./src/modules/wt-utils.js\");\n\n\n\n\nlet auth = function () {\n var _this = this;\n\n return {\n login: (username, password) => {\n return this.__privates.auth.__client.then(client => client.apis.auth.signIn({}, {\n requestBody: {\n username,\n password\n }\n })).then(response => {\n this.userId = response.data.userId;\n this.username = response.data.username;\n return this.__privates.auth.login(response.data.idToken, response.data.accessToken, response.data.refreshToken);\n });\n },\n providerLogin: (domain, token, displayname, deviceId) => {\n if (!token && typeof this.__privates.providerAuth === 'function') {\n ({\n token,\n displayname\n } = this.__privates.providerAuth());\n }\n\n return this.__privates.auth.__client.then(client => client.apis.auth.providerSignIn({}, {\n requestBody: {\n domain,\n token,\n ...(displayname && {\n displayname\n }),\n ...(deviceId && {\n deviceId\n })\n }\n })).then(response => {\n this.userId = response.data.userId;\n this.username = response.data.username;\n return this.__privates.auth.login(response.data.idToken, response.data.accessToken, response.data.refreshToken);\n });\n },\n getProviderAuth: () => {\n return this.__privates.providerAuth;\n },\n deviceLogin: salt => {\n return Object(_modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"getBrowserFingerprint\"])(this.__instanceType, salt).then(deviceId => Promise.all([deviceId, this.__privates.auth.__client])).then(_ref => {\n let [deviceId, client] = _ref;\n return client.apis.auth.deviceSignIn({}, {\n requestBody: {\n deviceId,\n domain: location.hostname\n }\n });\n }).then(response => {\n this.userId = response.data.userId;\n this.username = response.data.username;\n return this.__privates.auth.login(response.data.idToken, response.data.accessToken, response.data.refreshToken);\n });\n },\n logout: () => {\n return this.__privates.auth.logout();\n },\n isLoggedIn: () => {\n return this.__privates.auth.isLoggedIn();\n },\n setLanguage: language => {\n return this.__privates.auth.setLanguage(language);\n },\n getLanguage: () => {\n return this.__privates.auth.__language;\n },\n signUp: (username, password, email, phone) => {\n return this.__privates.auth.__client.then(client => client.apis.auth.signUp({}, {\n requestBody: {\n username,\n password,\n email,\n phone\n }\n }));\n },\n confirmSignUp: function (confirmationCode, username, displayname) {\n let isPublic = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;\n return _this.__privates.auth.__client.then(client => client.apis.auth.confirmSignUp({}, {\n requestBody: {\n confirmationCode,\n username,\n displayname,\n isPublic\n }\n })).then(response => {\n _this.userId = response.data.userId;\n _this.username = response.data.username;\n return _this.__privates.auth.login(response.data.idToken, response.data.accessToken, response.data.refreshToken);\n });\n },\n resendConfirmationCode: username => {\n return this.__privates.auth.__client.then(client => client.apis.auth.resendConfirmationCode({}, {\n requestBody: {\n username\n }\n }));\n },\n forgotPassword: username => {\n return this.__privates.auth.__client.then(client => client.apis.auth.forgotPassword({}, {\n requestBody: {\n username\n }\n }));\n },\n confirmForgotPassword: (username, confirmationCode, password) => {\n return this.__privates.auth.__client.then(client => client.apis.auth.confirmForgotPassword({}, {\n requestBody: {\n password,\n confirmationCode,\n username\n }\n }));\n },\n $on: (key, callback, that) => {\n return this.__privates.auth.on(key, callback, that || this);\n },\n $off: (key, callback, that) => {\n return this.__privates.auth.off(key, callback, that || this);\n },\n $clear: () => {\n return this.__privates.auth.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (auth);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/auth.js?");
9097
9108
 
9098
9109
  /***/ }),
9099
9110
 
@@ -9105,7 +9116,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _mod
9105
9116
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9106
9117
 
9107
9118
  "use strict";
9108
- eval("__webpack_require__.r(__webpack_exports__);\n\n\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _iterableToArray(iter) { if (typeof Symbol !== \"undefined\" && iter[Symbol.iterator] != null || iter[\"@@iterator\"] != null) return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }\n\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\nfunction _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nvar iot = function iot() {\n var _this = this;\n\n var __currentTopics = [];\n var __ = null;\n return {\n __promise: null,\n __reconnect: function __reconnect(err) {\n _this.__privates.iot.log('MQTT Error:', err, \"Is event error: \".concat(err instanceof Event));\n\n if (err instanceof Event && err.type === 'error') {\n _this.__privates.iot.log('SDK MQTT Reconnection attempt');\n\n clearTimeout(__);\n __ = setTimeout(function () {\n _this.iot.iotLogin(true, true).catch(function (e) {\n return _this.__privates.iot.log('MQTT Connection Error:', e);\n });\n }, 1000);\n }\n },\n __updateCredentials: function __updateCredentials() {\n _this.iot.getCredentials().then(function (response) {\n return _this.__privates.iot.updateWebSocketCredentials(response.data.credentials.accessKeyId, response.data.credentials.secretAccessKey, response.data.credentials.sessionToken, response.data.credentials.expiration);\n });\n },\n getCredentials: function getCredentials() {\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.auth.iotSignIn({}, {\n requestBody: {\n suggestedTopics: true,\n domain: location.hostname\n }\n });\n });\n },\n iotLogin: function iotLogin() {\n var subscribeToSuggestedTopics = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;\n var forceDisconnect = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n _this.iot.$off('error', _this.iot.__reconnect, _this);\n\n _this.iot.__promise = new Promise(function (resolve, reject) {\n _this.iot.getCredentials().then(function (response) {\n return Promise.all([response.data.suggestedTopics, _this.__privates.iot.connect(response.data.endpoint, response.data.clientId, response.data.region, response.data.credentials.accessKeyId, response.data.credentials.secretAccessKey, response.data.credentials.sessionToken, response.data.credentials.expiration, forceDisconnect)]);\n }).then(resolve).catch(reject);\n });\n\n var __currentTopicsCopy = [].concat(__currentTopics);\n\n __currentTopics.length = 0;\n\n _this.iot.__promise.then(function (_ref) {\n var _ref2 = _slicedToArray(_ref, 2),\n suggestedTopic = _ref2[0],\n instance = _ref2[1];\n\n return subscribeToSuggestedTopics ? Promise.all([].concat(_toConsumableArray(suggestedTopic), _toConsumableArray(__currentTopicsCopy)).map(function (topic) {\n return _this.iot.subscribe(topic);\n })).then(function () {\n return instance;\n }) : Promise.resolve(instance);\n }).then(function (instance) {\n _this.iot.$on('error', _this.iot.__reconnect, _this);\n\n _this.iot.$on('updateCredentials', _this.iot.__updateCredentials, _this);\n\n return instance;\n });\n\n return _this.iot.__promise;\n },\n iotLogout: function iotLogout() {\n var keepCurrentTopics = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n _this.iot.$off('error', _this.iot.__reconnect, _this);\n\n _this.iot.$off('updateCredentials', _this.iot.__updateCredentials, _this);\n\n if (!keepCurrentTopics) {\n __currentTopics.length = 0;\n }\n\n return _this.__privates.iot.disconnect().then(function () {\n _this.iot.__promise = null;\n return true;\n });\n },\n isConnected: function isConnected() {\n return _this.__privates.iot.isConnected();\n },\n subscribe: function subscribe(topic) {\n if (__currentTopics.indexOf(topic) === -1) {\n __currentTopics.push(topic);\n\n if (!_this.iot.__promise) return Promise.resolve('not_connected');\n return _this.iot.__promise.then(function () {\n return _this.__privates.iot.subscribe(topic);\n });\n }\n },\n unsubscribe: function unsubscribe(topic) {\n var index = __currentTopics.indexOf(topic);\n\n index > -1 && __currentTopics.splice(index, 1);\n if (!_this.iot.__promise) return Promise.resolve('not_connected');\n return _this.iot.__promise.then(function () {\n return _this.__privates.iot.unsubscribe(topic);\n });\n },\n send: function send(topic, message) {\n return _this.iot.__promise.then(function () {\n return _this.__privates.iot.send(topic, message);\n });\n },\n $once: function $once(key, callback, that) {\n return _this.__privates.iot.once(key, callback, that || _this);\n },\n $on: function $on(key, callback, that) {\n return _this.__privates.iot.on(key, callback, that || _this);\n },\n $off: function $off(key, callback, that) {\n return _this.__privates.iot.off(key, callback, that || _this);\n },\n $clear: function $clear() {\n return _this.__privates.iot.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (iot);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/iot.js?");
9119
+ eval("__webpack_require__.r(__webpack_exports__);\n\n\nlet iot = function () {\n var _this = this;\n\n let __currentTopics = [];\n let __ = null;\n return {\n __promise: null,\n __reconnect: err => {\n this.__privates.iot.log('MQTT Error:', err, \"Is event error: \".concat(err instanceof Event));\n\n if (err instanceof Event && err.type === 'error') {\n this.__privates.iot.log('SDK MQTT Reconnection attempt');\n\n clearTimeout(__);\n __ = setTimeout(() => {\n this.iot.iotLogin(true, true).catch(e => this.__privates.iot.log('MQTT Connection Error:', e));\n }, 1000);\n }\n },\n __updateCredentials: () => {\n this.iot.getCredentials().then(response => this.__privates.iot.updateWebSocketCredentials(response.data.credentials.accessKeyId, response.data.credentials.secretAccessKey, response.data.credentials.sessionToken, response.data.credentials.expiration));\n },\n getCredentials: () => {\n return this.__privates.auth.__client.then(client => client.apis.auth.iotSignIn({}, {\n requestBody: {\n suggestedTopics: true,\n domain: location.hostname\n }\n }));\n },\n iotLogin: function () {\n let subscribeToSuggestedTopics = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;\n let forceDisconnect = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n _this.iot.$off('error', _this.iot.__reconnect, _this);\n\n _this.iot.__promise = new Promise((resolve, reject) => {\n _this.iot.getCredentials().then(response => {\n return Promise.all([response.data.suggestedTopics, _this.__privates.iot.connect(response.data.endpoint, response.data.clientId, response.data.region, response.data.credentials.accessKeyId, response.data.credentials.secretAccessKey, response.data.credentials.sessionToken, response.data.credentials.expiration, forceDisconnect)]);\n }).then(resolve).catch(reject);\n });\n let __currentTopicsCopy = [...__currentTopics];\n __currentTopics.length = 0;\n\n _this.iot.__promise.then(_ref => {\n let [suggestedTopic, instance] = _ref;\n return subscribeToSuggestedTopics ? Promise.all([...suggestedTopic, ...__currentTopicsCopy].map(topic => _this.iot.subscribe(topic))).then(() => instance) : Promise.resolve(instance);\n }).then(instance => {\n _this.iot.$on('error', _this.iot.__reconnect, _this);\n\n _this.iot.$on('updateCredentials', _this.iot.__updateCredentials, _this);\n\n return instance;\n });\n\n return _this.iot.__promise;\n },\n iotLogout: function () {\n let keepCurrentTopics = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n _this.iot.$off('error', _this.iot.__reconnect, _this);\n\n _this.iot.$off('updateCredentials', _this.iot.__updateCredentials, _this);\n\n if (!keepCurrentTopics) {\n __currentTopics.length = 0;\n }\n\n return _this.__privates.iot.disconnect().then(() => {\n _this.iot.__promise = null;\n return true;\n });\n },\n isConnected: () => {\n return this.__privates.iot.isConnected();\n },\n subscribe: topic => {\n if (__currentTopics.indexOf(topic) === -1) {\n __currentTopics.push(topic);\n\n if (!this.iot.__promise) return Promise.resolve('not_connected');\n return this.iot.__promise.then(() => this.__privates.iot.subscribe(topic));\n }\n },\n unsubscribe: topic => {\n let index = __currentTopics.indexOf(topic);\n\n index > -1 && __currentTopics.splice(index, 1);\n if (!this.iot.__promise) return Promise.resolve('not_connected');\n return this.iot.__promise.then(() => this.__privates.iot.unsubscribe(topic));\n },\n send: (topic, message) => {\n return this.iot.__promise.then(() => this.__privates.iot.send(topic, message));\n },\n $once: (key, callback, that) => {\n return this.__privates.iot.once(key, callback, that || this);\n },\n $on: (key, callback, that) => {\n return this.__privates.iot.on(key, callback, that || this);\n },\n $off: (key, callback, that) => {\n return this.__privates.iot.off(key, callback, that || this);\n },\n $clear: () => {\n return this.__privates.iot.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (iot);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/iot.js?");
9109
9120
 
9110
9121
  /***/ }),
9111
9122
 
@@ -9117,7 +9128,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n\n\nfunction _toConsumableArr
9117
9128
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9118
9129
 
9119
9130
  "use strict";
9120
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/wt-utils */ \"./src/modules/wt-utils.js\");\n/* harmony import */ var _modules_wt_emitter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../modules/wt-emitter */ \"./src/modules/wt-emitter.js\");\n/* harmony import */ var _modules_sync_modules_sync_hls__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../modules/sync-modules/sync-hls */ \"./src/modules/sync-modules/sync-hls.js\");\n/* harmony import */ var _modules_sync_modules_sync_hls_vod__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../modules/sync-modules/sync-hls-vod */ \"./src/modules/sync-modules/sync-hls-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_native_hls_vod__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../modules/sync-modules/sync-native-hls-vod */ \"./src/modules/sync-modules/sync-native-hls-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_native_hls__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../modules/sync-modules/sync-native-hls */ \"./src/modules/sync-modules/sync-native-hls.js\");\n/* harmony import */ var _modules_sync_modules_sync_shaka_dash__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../modules/sync-modules/sync-shaka-dash */ \"./src/modules/sync-modules/sync-shaka-dash.js\");\n/* harmony import */ var _modules_sync_modules_sync_shaka_dash_vod__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../modules/sync-modules/sync-shaka-dash-vod */ \"./src/modules/sync-modules/sync-shaka-dash-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_dash__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../modules/sync-modules/sync-dash */ \"./src/modules/sync-modules/sync-dash.js\");\n/* harmony import */ var _modules_sync_modules_sync_dash_vod__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../modules/sync-modules/sync-dash-vod */ \"./src/modules/sync-modules/sync-dash-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_doris__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../modules/sync-modules/sync-doris */ \"./src/modules/sync-modules/sync-doris.js\");\n/* harmony import */ var _modules_sync_modules_sync_disabled__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../modules/sync-modules/sync-disabled */ \"./src/modules/sync-modules/sync-disabled.js\");\n/* harmony import */ var _modules_sync_modules_sync_dazn_dash__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../modules/sync-modules/sync-dazn-dash */ \"./src/modules/sync-modules/sync-dazn-dash.js\");\n/* harmony import */ var _modules_sync_modules_sync_universal__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../modules/sync-modules/sync-universal */ \"./src/modules/sync-modules/sync-universal.js\");\n\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _iterableToArray(iter) { if (typeof Symbol !== \"undefined\" && iter[Symbol.iterator] != null || iter[\"@@iterator\"] != null) return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\n\n // SYNCHRONISATION MODULES\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nvar roomSession = function roomSession(_ref, room, wt) {\n var _this4 = this;\n\n var roomId = _ref.roomId,\n pinHash = _ref.pinHash,\n isTalkback = _ref.isTalkback,\n isMonitor = _ref.isMonitor,\n isInstructor = _ref.isInstructor;\n var primaryRoomId = roomId;\n var publicCustomEvents = ['changePlayerSource', 'chatMessage', 'userUpdate', 'reconnecting', 'connecting', 'remoteMuted', 'scaling'];\n\n var addEvents = function addEvents(events) {\n publicCustomEvents = [].concat(_toConsumableArray(publicCustomEvents), _toConsumableArray(events));\n };\n\n var removeEvents = function removeEvents(events) {\n publicCustomEvents = publicCustomEvents.filter(function (ev) {\n return events.indexOf(ev) === -1;\n });\n };\n\n var emitter = Object(_modules_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])();\n\n var alpTimeoutId = null;\n\n var ___; // return object\n\n\n room.on('addLocalParticipant', function () {\n // TODO: this doesnt seem to be fixable until we switch to different type of messaging\n // At some random case we don't get message back if we don't wait\n clearTimeout(alpTimeoutId);\n alpTimeoutId = setTimeout(function () {\n ___.__requestMuteStatus();\n }, 2000);\n });\n room.on('localMuted', function (_ref2) {\n var type = _ref2.type,\n value = _ref2.value;\n\n ___.sendSystemMessage('remote_muted', {\n type: type,\n value: value\n });\n });\n room.on('data', function (data) {\n ___.__parseDataEvents(data);\n });\n return ___ = {\n syncModule: null,\n playerInterface: null,\n\n get userId() {\n return room.userId;\n },\n\n get roomId() {\n return roomId;\n },\n\n get sessionId() {\n return room.sessionId;\n },\n\n get constructId() {\n return room.constructId;\n },\n\n destroy: function destroy() {\n var _this = this;\n\n clearTimeout(alpTimeoutId);\n this.detachPlayer();\n return room.destroy().finally(function () {\n _this.$clear();\n\n return true;\n });\n },\n iceRestart: function iceRestart() {\n return room._iceRestart(room.handleId);\n },\n connect: function connect() {\n var _this2 = this;\n\n var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref3$reactooRoomId = _ref3.reactooRoomId,\n reactooRoomId = _ref3$reactooRoomId === void 0 ? null : _ref3$reactooRoomId;\n\n emitter.emit('connecting', true);\n clearTimeout(alpTimeoutId);\n return Promise.all([wt.room.__joinRoom({\n roomId: reactooRoomId || primaryRoomId,\n pinHash: pinHash,\n isTalkback: isTalkback,\n isMonitor: isMonitor,\n isInstructor: isInstructor\n }), wt.user.getUserSelf()]).then(function (_ref4) {\n var _roomData$data;\n\n var _ref5 = _slicedToArray(_ref4, 2),\n roomData = _ref5[0],\n userData = _ref5[1];\n\n // Happens when we reroute user to a different room\n if ((roomData === null || roomData === void 0 ? void 0 : (_roomData$data = roomData.data) === null || _roomData$data === void 0 ? void 0 : _roomData$data.reactooRoomId) !== roomId) {\n roomId = roomData.data.reactooRoomId;\n emitter.emit('changeRoomId', roomId);\n }\n\n return Promise.all([roomData, userData]);\n }).then(function (_ref6) {\n var _ref7 = _slicedToArray(_ref6, 2),\n roomData = _ref7[0],\n userData = _ref7[1];\n\n return Promise.all([roomData, userData, _this2.setRoomVars()]);\n }).then(function (_ref8) {\n var _ref9 = _slicedToArray(_ref8, 3),\n roomData = _ref9[0],\n userData = _ref9[1],\n _ = _ref9[2];\n\n return Promise.all([roomData, userData, room.connect(roomData.data.roomId, roomData.data.pin, roomData.data.href, roomData.data.iceServers, roomData.data.accessToken, roomData.data.display, roomData.data.userId, roomData.data.webrtcVersion, roomData.data.bitrate ? parseInt(roomData.data.bitrate) : 0, isMonitor, roomData.data.recordingFilename)]);\n }).finally(function () {\n emitter.emit('connecting', false);\n });\n },\n disconnect: function disconnect(dontWaitForResponses) {\n clearTimeout(alpTimeoutId);\n return room.disconnect(dontWaitForResponses);\n },\n //TODO: refactor restart method\n restart: function restart() {\n var _handle$webrtcStuff,\n _this3 = this;\n\n var _ref10 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref10$isObserver = _ref10.isObserver,\n isObserver = _ref10$isObserver === void 0 ? false : _ref10$isObserver,\n _ref10$reactooRoomId = _ref10.reactooRoomId,\n reactooRoomId = _ref10$reactooRoomId === void 0 ? null : _ref10$reactooRoomId;\n\n emitter.emit('reconnecting', true);\n room.isRestarting = true;\n var wasPublished = room._isPublished;\n\n var handle = room._getHandle(room.handleId);\n\n var stream = null;\n\n if (handle !== null && handle !== void 0 && (_handle$webrtcStuff = handle.webrtcStuff) !== null && _handle$webrtcStuff !== void 0 && _handle$webrtcStuff.stream && wasPublished) {\n stream = handle.webrtcStuff.stream;\n }\n\n return this.disconnect().then(function () {\n return Object(_modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(1000);\n }) //TODO: remove 1000ms wait by waiting for proper events from janus\n .then(function () {\n return _this3.connect({\n reactooRoomId: reactooRoomId\n });\n }).then(function () {\n if (isObserver) {\n return _this3.publishLocal(null);\n } else if (stream) {\n return _this3.publishLocal(stream);\n } else return Promise.resolve();\n }).then(function () {\n room.isRestarting = false;\n emitter.emit('reconnecting', false);\n return 1;\n }).catch(function (error) {\n room.isRestarting = false;\n emitter.emit('reconnecting', false);\n emitter.emit('error', {\n type: 'error',\n id: 26,\n message: 'reconnecting failed',\n data: error\n });\n return Promise.reject(0);\n });\n },\n getStats: function getStats() {\n var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n return room._getStats(type);\n },\n getRoomParticipants: function getRoomParticipants() {\n return room._participants;\n },\n __parseDataEvents: function __parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'message') {\n if (msg.action === 'pending_shutdown' || msg.action === 'shutting_down') {\n emitter.emit('scaling');\n this.restart(); // current videoroom was reassigned to a different WebRTC instance\n } else if (msg.action === 'force_restart') {\n this.restart();\n } else if (msg.action === 'user_update_displayname' || msg.action === 'user_update_avatar' || msg.action === 'user_update_customattributes' || msg.action === 'user_update_privateattributes') {\n emitter.emit('userUpdate', msg.text);\n } else if (msg.action === 'observer_connecting' || msg.action === 'talkback_connecting' || msg.action === 'instructor_connecting') {\n this.setRoomVars().catch(function (e) {\n room._log('Setting observers failed, this will cause issues', e);\n });\n } else if (msg.action === 'bitrate_changed') {\n this.setBitrateCap(msg.text);\n } else if (msg.user_action === 'chat_message') {\n emitter.emit('chatMessage', msg);\n } else if (msg.user_action === 'remote_muted') {\n if (msg.from !== room.userId) {\n emitter.emit('remoteMuted', _objectSpread({\n userId: msg.from\n }, msg.text && JSON.parse(msg.text)));\n }\n } else if (msg.user_action === 'remote_muted_request') {\n if (msg.from !== room.userId) {\n this.__sendMuteStatus();\n }\n }\n }\n },\n renderPlayer: function renderPlayer(playerWrapper, fullscreenElement, roomId) {\n try {\n this.syncModule = Object(_modules_sync_modules_sync_universal__WEBPACK_IMPORTED_MODULE_13__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n this.playerInterface = wt.__privates.playerFactory(playerWrapper, fullscreenElement, this.syncModule.getHandlers(), {\n roomId: roomId\n });\n this.syncModule.initialize({\n playerInterface: this.playerInterface\n });\n return true;\n } catch (e) {\n return false;\n }\n },\n attachPlayer: function attachPlayer(type, inputs) {\n this.detachPlayer();\n\n if (type === 'hlsjs') {\n this.syncModule = Object(_modules_sync_modules_sync_hls__WEBPACK_IMPORTED_MODULE_2__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'hlsjs-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_hls_vod__WEBPACK_IMPORTED_MODULE_3__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'hlsnative-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_native_hls_vod__WEBPACK_IMPORTED_MODULE_4__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'hlsnative') {\n this.syncModule = Object(_modules_sync_modules_sync_native_hls__WEBPACK_IMPORTED_MODULE_5__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'shaka-dash-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_shaka_dash_vod__WEBPACK_IMPORTED_MODULE_7__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'shaka-dash') {\n this.syncModule = Object(_modules_sync_modules_sync_shaka_dash__WEBPACK_IMPORTED_MODULE_6__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'dashjs') {\n this.syncModule = Object(_modules_sync_modules_sync_dash__WEBPACK_IMPORTED_MODULE_8__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'dashjs-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_dash_vod__WEBPACK_IMPORTED_MODULE_9__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'doris') {\n this.syncModule = Object(_modules_sync_modules_sync_doris__WEBPACK_IMPORTED_MODULE_10__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'dazn-dash') {\n this.syncModule = Object(_modules_sync_modules_sync_dazn_dash__WEBPACK_IMPORTED_MODULE_12__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'disabled') {\n this.syncModule = Object(_modules_sync_modules_sync_disabled__WEBPACK_IMPORTED_MODULE_11__[\"default\"])({\n room: room,\n wt: wt,\n roomSession: this,\n emitter: emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else {\n room._log('Synchronisation type not recognised');\n }\n },\n detachPlayer: function detachPlayer() {\n if (this.syncModule) {\n this.playerInterface = null;\n this.syncModule.destroy();\n\n if (this.syncModule.__events) {\n removeEvents(this.syncModule.__events);\n }\n\n this.syncModule = null;\n }\n },\n setRoomVars: function setRoomVars() {\n return wt.room.getRoomById(roomId, pinHash).then(function (r) {\n var _r$data$classroom;\n\n // setting observers userId's so we can ignore them when creating participant\n room.setObserverIds(r.data.allowedObservers);\n room.setTalkbackIds(r.data.allowedTalkbacks);\n room.setInstructorId((_r$data$classroom = r.data.classroom) === null || _r$data$classroom === void 0 ? void 0 : _r$data$classroom.instructorUserId);\n });\n },\n publishLocal: function publishLocal() {\n var stream = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n\n var _ref11 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n _ref11$keepAudio = _ref11.keepAudio,\n keepAudio = _ref11$keepAudio === void 0 ? false : _ref11$keepAudio,\n _ref11$keepVideo = _ref11.keepVideo,\n keepVideo = _ref11$keepVideo === void 0 ? false : _ref11$keepVideo;\n\n return room.publishLocal(stream, {\n keepAudio: keepAudio,\n keepVideo: keepVideo\n });\n },\n unpublishLocal: function unpublishLocal() {\n return room.unpublishLocal();\n },\n toggleAudio: function toggleAudio(value) {\n return room.toggleAudio(value);\n },\n toggleVideo: function toggleVideo() {\n return room.toggleVideo();\n },\n setBitrateCap: function setBitrateCap(bitrate) {\n if (isInstructor) {\n return;\n }\n\n return room.sendMessage(room.handleId, {\n \"body\": {\n \"request\": \"configure\",\n \"bitrate\": parseInt(bitrate)\n }\n }).catch(function () {\n return null;\n });\n },\n switchChannel: function switchChannel(channelId) {\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: channelId,\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n },\n sendSystemMessage: function sendSystemMessage(action) {\n var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n var to = arguments.length > 2 ? arguments[2] : undefined;\n var set_master = arguments.length > 3 ? arguments[3] : undefined;\n return room.sendMessage(room.handleId, {\n body: _objectSpread(_objectSpread({\n action: action,\n request: \"message\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n text: JSON.stringify(value)\n }, to && Array.isArray(to) ? {\n tos: to\n } : {\n to: to\n }), set_master && {\n set_master: set_master\n })\n });\n },\n sendChatMessage: function sendChatMessage(text, to) {\n return room.sendMessage(room.handleId, {\n body: _objectSpread({\n action: \"chat_message\",\n request: \"message\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n text: text\n }, to && Array.isArray(to) ? {\n tos: to\n } : {\n to: to\n })\n });\n },\n __requestMuteStatus: function __requestMuteStatus() {\n this.sendSystemMessage('remote_muted_request');\n },\n __sendMuteStatus: function __sendMuteStatus() {\n this.sendSystemMessage('remote_muted', {\n type: 'video',\n value: room.isVideoMuted\n });\n this.sendSystemMessage('remote_muted', {\n type: 'audio',\n value: room.isAudioMuted\n });\n },\n $on: function $on(key, callback, that) {\n emitter.on(key, callback, that || _this4);\n room.on(key, callback, that || _this4);\n },\n $off: function $off(key, callback, that) {\n emitter.on(key, callback, that || _this4);\n room.on(key, callback, that || _this4);\n },\n $clear: function $clear() {\n room.clear();\n emitter.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (roomSession);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/room-session.js?");
9131
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/wt-utils */ \"./src/modules/wt-utils.js\");\n/* harmony import */ var _modules_wt_emitter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../modules/wt-emitter */ \"./src/modules/wt-emitter.js\");\n/* harmony import */ var _modules_sync_modules_sync_hls__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../modules/sync-modules/sync-hls */ \"./src/modules/sync-modules/sync-hls.js\");\n/* harmony import */ var _modules_sync_modules_sync_hls_vod__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../modules/sync-modules/sync-hls-vod */ \"./src/modules/sync-modules/sync-hls-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_native_hls_vod__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../modules/sync-modules/sync-native-hls-vod */ \"./src/modules/sync-modules/sync-native-hls-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_native_hls__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../modules/sync-modules/sync-native-hls */ \"./src/modules/sync-modules/sync-native-hls.js\");\n/* harmony import */ var _modules_sync_modules_sync_shaka_dash__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../modules/sync-modules/sync-shaka-dash */ \"./src/modules/sync-modules/sync-shaka-dash.js\");\n/* harmony import */ var _modules_sync_modules_sync_shaka_dash_vod__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../modules/sync-modules/sync-shaka-dash-vod */ \"./src/modules/sync-modules/sync-shaka-dash-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_dash__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../modules/sync-modules/sync-dash */ \"./src/modules/sync-modules/sync-dash.js\");\n/* harmony import */ var _modules_sync_modules_sync_dash_vod__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../modules/sync-modules/sync-dash-vod */ \"./src/modules/sync-modules/sync-dash-vod.js\");\n/* harmony import */ var _modules_sync_modules_sync_doris__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../modules/sync-modules/sync-doris */ \"./src/modules/sync-modules/sync-doris.js\");\n/* harmony import */ var _modules_sync_modules_sync_disabled__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../modules/sync-modules/sync-disabled */ \"./src/modules/sync-modules/sync-disabled.js\");\n/* harmony import */ var _modules_sync_modules_sync_dazn_dash__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../modules/sync-modules/sync-dazn-dash */ \"./src/modules/sync-modules/sync-dazn-dash.js\");\n/* harmony import */ var _modules_sync_modules_sync_universal__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../modules/sync-modules/sync-universal */ \"./src/modules/sync-modules/sync-universal.js\");\n\n\n\n // SYNCHRONISATION MODULES\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nlet roomSession = function (_ref, room, wt) {\n let {\n roomId,\n pinHash,\n isTalkback,\n isMonitor,\n isInstructor\n } = _ref;\n let primaryRoomId = roomId;\n let publicCustomEvents = ['changePlayerSource', 'chatMessage', 'userUpdate', 'reconnecting', 'connecting', 'remoteMuted', 'scaling'];\n\n const addEvents = events => {\n publicCustomEvents = [...publicCustomEvents, ...events];\n };\n\n const removeEvents = events => {\n publicCustomEvents = publicCustomEvents.filter(ev => events.indexOf(ev) === -1);\n };\n\n const emitter = Object(_modules_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])();\n\n let alpTimeoutId = null;\n\n let ___; // return object\n\n\n room.on('addLocalParticipant', () => {\n // TODO: this doesnt seem to be fixable until we switch to different type of messaging\n // At some random case we don't get message back if we don't wait\n clearTimeout(alpTimeoutId);\n alpTimeoutId = setTimeout(() => {\n ___.__requestMuteStatus();\n }, 2000);\n });\n room.on('localMuted', _ref2 => {\n let {\n type,\n value\n } = _ref2;\n\n ___.sendSystemMessage('remote_muted', {\n type,\n value\n });\n });\n room.on('data', data => {\n ___.__parseDataEvents(data);\n });\n return ___ = {\n syncModule: null,\n playerInterface: null,\n\n get userId() {\n return room.userId;\n },\n\n get roomId() {\n return roomId;\n },\n\n get sessionId() {\n return room.sessionId;\n },\n\n get constructId() {\n return room.constructId;\n },\n\n destroy: function () {\n clearTimeout(alpTimeoutId);\n this.detachPlayer();\n return room.destroy().finally(() => {\n this.$clear();\n return true;\n });\n },\n iceRestart: function () {\n return room._iceRestart(room.handleId);\n },\n connect: function () {\n let {\n reactooRoomId = null\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n emitter.emit('connecting', true);\n clearTimeout(alpTimeoutId);\n return Promise.all([wt.room.__joinRoom({\n roomId: reactooRoomId || primaryRoomId,\n pinHash,\n isTalkback,\n isMonitor,\n isInstructor\n }), wt.user.getUserSelf()]).then(_ref3 => {\n var _roomData$data;\n\n let [roomData, userData] = _ref3;\n\n // Happens when we reroute user to a different room\n if ((roomData === null || roomData === void 0 ? void 0 : (_roomData$data = roomData.data) === null || _roomData$data === void 0 ? void 0 : _roomData$data.reactooRoomId) !== roomId) {\n roomId = roomData.data.reactooRoomId;\n emitter.emit('changeRoomId', roomId);\n }\n\n return Promise.all([roomData, userData]);\n }).then(_ref4 => {\n let [roomData, userData] = _ref4;\n return Promise.all([roomData, userData, this.setRoomVars()]);\n }).then(_ref5 => {\n let [roomData, userData, _] = _ref5;\n return Promise.all([roomData, userData, room.connect(roomData.data.roomId, roomData.data.pin, roomData.data.href, roomData.data.iceServers, roomData.data.accessToken, roomData.data.display, roomData.data.userId, roomData.data.webrtcVersion, roomData.data.bitrate ? parseInt(roomData.data.bitrate) : 0, isMonitor, roomData.data.recordingFilename)]);\n }).finally(() => {\n emitter.emit('connecting', false);\n });\n },\n disconnect: function (dontWaitForResponses) {\n clearTimeout(alpTimeoutId);\n return room.disconnect(dontWaitForResponses);\n },\n //TODO: refactor restart method\n restart: function () {\n var _handle$webrtcStuff;\n\n let {\n isObserver = false,\n reactooRoomId = null\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n emitter.emit('reconnecting', true);\n room.isRestarting = true;\n let wasPublished = room._isPublished;\n\n let handle = room._getHandle(room.handleId);\n\n let stream = null;\n\n if (handle !== null && handle !== void 0 && (_handle$webrtcStuff = handle.webrtcStuff) !== null && _handle$webrtcStuff !== void 0 && _handle$webrtcStuff.stream && wasPublished) {\n stream = handle.webrtcStuff.stream;\n }\n\n return this.disconnect().then(() => Object(_modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(1000)) //TODO: remove 1000ms wait by waiting for proper events from janus\n .then(() => this.connect({\n reactooRoomId\n })).then(() => {\n if (isObserver) {\n return this.publishLocal(null);\n } else if (stream) {\n return this.publishLocal(stream);\n } else return Promise.resolve();\n }).then(() => {\n room.isRestarting = false;\n emitter.emit('reconnecting', false);\n return 1;\n }).catch(error => {\n room.isRestarting = false;\n emitter.emit('reconnecting', false);\n emitter.emit('error', {\n type: 'error',\n id: 26,\n message: 'reconnecting failed',\n data: error\n });\n return Promise.reject(0);\n });\n },\n getStats: function () {\n let type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n return room._getStats(type);\n },\n getRoomParticipants: function () {\n return room._participants;\n },\n __parseDataEvents: function () {\n let msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'message') {\n if (msg.action === 'pending_shutdown' || msg.action === 'shutting_down') {\n emitter.emit('scaling');\n this.restart(); // current videoroom was reassigned to a different WebRTC instance\n } else if (msg.action === 'force_restart') {\n this.restart();\n } else if (msg.action === 'user_update_displayname' || msg.action === 'user_update_avatar' || msg.action === 'user_update_customattributes' || msg.action === 'user_update_privateattributes') {\n emitter.emit('userUpdate', msg.text);\n } else if (msg.action === 'observer_connecting' || msg.action === 'talkback_connecting' || msg.action === 'instructor_connecting') {\n this.setRoomVars().catch(e => {\n room._log('Setting observers failed, this will cause issues', e);\n });\n } else if (msg.action === 'bitrate_changed') {\n this.setBitrateCap(msg.text);\n } else if (msg.user_action === 'chat_message') {\n emitter.emit('chatMessage', msg);\n } else if (msg.user_action === 'remote_muted') {\n if (msg.from !== room.userId) {\n emitter.emit('remoteMuted', {\n userId: msg.from,\n ...(msg.text && JSON.parse(msg.text))\n });\n }\n } else if (msg.user_action === 'remote_muted_request') {\n if (msg.from !== room.userId) {\n this.__sendMuteStatus();\n }\n }\n }\n },\n renderPlayer: function (playerWrapper, fullscreenElement, roomId) {\n try {\n this.syncModule = Object(_modules_sync_modules_sync_universal__WEBPACK_IMPORTED_MODULE_13__[\"default\"])({\n room,\n wt,\n roomSession: this,\n emitter\n });\n this.playerInterface = wt.__privates.playerFactory(playerWrapper, fullscreenElement, this.syncModule.getHandlers(), {\n roomId\n });\n this.syncModule.initialize({\n playerInterface: this.playerInterface\n });\n return true;\n } catch (e) {\n return false;\n }\n },\n attachPlayer: function (type, inputs) {\n this.detachPlayer();\n\n if (type === 'hlsjs') {\n this.syncModule = Object(_modules_sync_modules_sync_hls__WEBPACK_IMPORTED_MODULE_2__[\"default\"])({\n room,\n wt,\n roomSession: this,\n emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'hlsjs-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_hls_vod__WEBPACK_IMPORTED_MODULE_3__[\"default\"])({\n room,\n wt,\n roomSession: this,\n emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'hlsnative-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_native_hls_vod__WEBPACK_IMPORTED_MODULE_4__[\"default\"])({\n room,\n wt,\n roomSession: this,\n emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'hlsnative') {\n this.syncModule = Object(_modules_sync_modules_sync_native_hls__WEBPACK_IMPORTED_MODULE_5__[\"default\"])({\n room,\n wt,\n roomSession: this,\n emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'shaka-dash-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_shaka_dash_vod__WEBPACK_IMPORTED_MODULE_7__[\"default\"])({\n room,\n wt,\n roomSession: this,\n emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'shaka-dash') {\n this.syncModule = Object(_modules_sync_modules_sync_shaka_dash__WEBPACK_IMPORTED_MODULE_6__[\"default\"])({\n room,\n wt,\n roomSession: this,\n emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'dashjs') {\n this.syncModule = Object(_modules_sync_modules_sync_dash__WEBPACK_IMPORTED_MODULE_8__[\"default\"])({\n room,\n wt,\n roomSession: this,\n emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'dashjs-vod') {\n this.syncModule = Object(_modules_sync_modules_sync_dash_vod__WEBPACK_IMPORTED_MODULE_9__[\"default\"])({\n room,\n wt,\n roomSession: this,\n emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'doris') {\n this.syncModule = Object(_modules_sync_modules_sync_doris__WEBPACK_IMPORTED_MODULE_10__[\"default\"])({\n room,\n wt,\n roomSession: this,\n emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'dazn-dash') {\n this.syncModule = Object(_modules_sync_modules_sync_dazn_dash__WEBPACK_IMPORTED_MODULE_12__[\"default\"])({\n room,\n wt,\n roomSession: this,\n emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else if (type === 'disabled') {\n this.syncModule = Object(_modules_sync_modules_sync_disabled__WEBPACK_IMPORTED_MODULE_11__[\"default\"])({\n room,\n wt,\n roomSession: this,\n emitter\n });\n\n if (this.syncModule.__events) {\n addEvents(this.syncModule.__events);\n }\n\n this.syncModule.initialize(inputs);\n } else {\n room._log('Synchronisation type not recognised');\n }\n },\n detachPlayer: function () {\n if (this.syncModule) {\n this.playerInterface = null;\n this.syncModule.destroy();\n\n if (this.syncModule.__events) {\n removeEvents(this.syncModule.__events);\n }\n\n this.syncModule = null;\n }\n },\n setRoomVars: () => {\n return wt.room.getRoomById(roomId, pinHash).then(r => {\n var _r$data$classroom;\n\n // setting observers userId's so we can ignore them when creating participant\n room.setObserverIds(r.data.allowedObservers);\n room.setTalkbackIds(r.data.allowedTalkbacks);\n room.setInstructorId((_r$data$classroom = r.data.classroom) === null || _r$data$classroom === void 0 ? void 0 : _r$data$classroom.instructorUserId);\n });\n },\n publishLocal: function () {\n let stream = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let {\n keepAudio = false,\n keepVideo = false\n } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n return room.publishLocal(stream, {\n keepAudio,\n keepVideo\n });\n },\n unpublishLocal: () => {\n return room.unpublishLocal();\n },\n toggleAudio: value => {\n return room.toggleAudio(value);\n },\n toggleVideo: () => {\n return room.toggleVideo();\n },\n setBitrateCap: bitrate => {\n if (isInstructor) {\n return;\n }\n\n return room.sendMessage(room.handleId, {\n \"body\": {\n \"request\": \"configure\",\n \"bitrate\": parseInt(bitrate)\n }\n }).catch(() => null);\n },\n switchChannel: channelId => {\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: channelId,\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n },\n sendSystemMessage: function (action) {\n let value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n let to = arguments.length > 2 ? arguments[2] : undefined;\n let set_master = arguments.length > 3 ? arguments[3] : undefined;\n return room.sendMessage(room.handleId, {\n body: {\n action,\n request: \"message\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n text: JSON.stringify(value),\n ...(to && Array.isArray(to) ? {\n tos: to\n } : {\n to\n }),\n ...(set_master && {\n set_master\n })\n }\n });\n },\n sendChatMessage: (text, to) => {\n return room.sendMessage(room.handleId, {\n body: {\n action: \"chat_message\",\n request: \"message\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n text,\n ...(to && Array.isArray(to) ? {\n tos: to\n } : {\n to\n })\n }\n });\n },\n __requestMuteStatus: function () {\n this.sendSystemMessage('remote_muted_request');\n },\n __sendMuteStatus: function () {\n this.sendSystemMessage('remote_muted', {\n type: 'video',\n value: room.isVideoMuted\n });\n this.sendSystemMessage('remote_muted', {\n type: 'audio',\n value: room.isAudioMuted\n });\n },\n $on: (key, callback, that) => {\n emitter.on(key, callback, that || this);\n room.on(key, callback, that || this);\n },\n $off: (key, callback, that) => {\n emitter.on(key, callback, that || this);\n room.on(key, callback, that || this);\n },\n $clear: function () {\n room.clear();\n emitter.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (roomSession);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/room-session.js?");
9121
9132
 
9122
9133
  /***/ }),
9123
9134
 
@@ -9129,7 +9140,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _mod
9129
9140
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9130
9141
 
9131
9142
  "use strict";
9132
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _room_session__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./room-session */ \"./src/models/room-session.js\");\n/* harmony import */ var _streaming_session__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./streaming-session */ \"./src/models/streaming-session.js\");\n\n\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _iterableToArray(iter) { if (typeof Symbol !== \"undefined\" && iter[Symbol.iterator] != null || iter[\"@@iterator\"] != null) return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n\n\n\nvar room = function room() {\n var _this = this;\n\n var roomSessions = [];\n\n var setExitListeners = function setExitListeners() {\n window.addEventListener('pagehide', function (event) {\n if (!event.persisted) {\n _this.room.destroySessions();\n }\n });\n window.addEventListener('beforeunload', function () {\n _this.room.destroySessions();\n });\n };\n\n setExitListeners();\n return {\n //TODO: new model\n integration: function integration() {\n var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.system.integration({\n type: _this.__instanceType\n }, {\n requestBody: _objectSpread({}, data),\n requestInterceptor: function requestInterceptor(req) {\n if (!req.headers) {\n req.headers = {};\n }\n\n req.headers['Authorization'] = 'Bearer ' + localStorage.getItem('rwt_idToken');\n return req;\n }\n });\n });\n },\n //TODO: new model\n getAnalytics: function getAnalytics() {\n var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.system.getAnalytics(_objectSpread({\n instanceType: _this.__instanceType\n }, data));\n });\n },\n sendChatMessage: function sendChatMessage(_ref) {\n var roomId = _ref.roomId,\n message = _ref.message,\n options = _ref.options,\n senderUserId = _ref.senderUserId;\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.sendRoomMessage({}, {\n requestBody: {\n roomId: roomId,\n message: message,\n options: options,\n senderUserId: senderUserId\n }\n });\n });\n },\n createRoom: function createRoom() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n title = _ref2.title,\n description = _ref2.description,\n isPublic = _ref2.isPublic,\n isListed = _ref2.isListed,\n isStudioLayout = _ref2.isStudioLayout,\n allowedParticipants = _ref2.allowedParticipants,\n wtChannelId = _ref2.wtChannelId,\n isHd = _ref2.isHd,\n disableSync = _ref2.disableSync,\n reduceRoomControls = _ref2.reduceRoomControls,\n muteParticipantOnJoin = _ref2.muteParticipantOnJoin,\n hasStudioChat = _ref2.hasStudioChat,\n maxParticipants = _ref2.maxParticipants,\n customAttributes = _ref2.customAttributes;\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.createRoom({}, {\n requestBody: {\n title: title,\n description: description,\n isPublic: isPublic,\n isListed: isListed,\n isStudioLayout: isStudioLayout,\n instanceType: _this.__instanceType,\n allowedParticipants: allowedParticipants,\n wtChannelId: wtChannelId,\n isHd: isHd,\n disableSync: disableSync,\n reduceRoomControls: reduceRoomControls,\n muteParticipantOnJoin: muteParticipantOnJoin,\n hasStudioChat: hasStudioChat,\n maxParticipants: maxParticipants,\n customAttributes: customAttributes\n }\n });\n });\n },\n updateRoom: function updateRoom() {\n var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n roomId = _ref3.roomId,\n title = _ref3.title,\n description = _ref3.description,\n isPublic = _ref3.isPublic,\n isListed = _ref3.isListed,\n allowedParticipants = _ref3.allowedParticipants,\n recordings = _ref3.recordings,\n slug = _ref3.slug,\n password = _ref3.password,\n maxParticipants = _ref3.maxParticipants,\n _ref3$setInstanceType = _ref3.setInstanceType,\n setInstanceType = _ref3$setInstanceType === void 0 ? false : _ref3$setInstanceType,\n wtChannelId = _ref3.wtChannelId,\n isHd = _ref3.isHd,\n isStudioLayout = _ref3.isStudioLayout,\n hasStudioChat = _ref3.hasStudioChat,\n reduceRoomControls = _ref3.reduceRoomControls,\n muteParticipantOnJoin = _ref3.muteParticipantOnJoin,\n disableSync = _ref3.disableSync,\n defaultRegion = _ref3.defaultRegion,\n customAttributes = _ref3.customAttributes,\n dotAttribute = _ref3.dotAttribute;\n\n var _da = dotAttribute ? Array.isArray(dotAttribute) ? dotAttribute.reduce(function (p, cv) {\n return (p[cv.name] = cv.value) && p || p;\n }, {}) : _defineProperty({}, dotAttribute.name, dotAttribute.value) : {};\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.updateRoom({\n id: roomId\n }, {\n requestBody: _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, _da), {}, {\n title: title,\n description: description,\n slug: slug,\n password: password,\n isPublic: isPublic,\n isListed: isListed,\n isHd: isHd,\n isStudioLayout: isStudioLayout,\n hasStudioChat: hasStudioChat,\n maxParticipants: maxParticipants,\n reduceRoomControls: reduceRoomControls,\n muteParticipantOnJoin: muteParticipantOnJoin,\n disableSync: disableSync,\n defaultRegion: defaultRegion,\n customAttributes: customAttributes,\n wtChannelId: wtChannelId\n }, setInstanceType && {\n instanceType: setInstanceType === true ? _this.__instanceType : setInstanceType\n }), allowedParticipants && {\n allowedParticipants: allowedParticipants\n }), recordings && {\n recordings: recordings\n })\n });\n });\n },\n deleteRoom: function deleteRoom(roomId) {\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.deleteRoom({\n id: roomId\n });\n });\n },\n leaveRoom: function leaveRoom(roomId) {\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.leave({\n roomId: roomId\n });\n });\n },\n updateLayout: function updateLayout(_ref5) {\n var roomId = _ref5.roomId,\n operation = _ref5.operation,\n name = _ref5.name,\n attributeName = _ref5.attributeName,\n value = _ref5.value,\n target = _ref5.target;\n //operation : clearLayouts, setLayout, setLayouts, unsetLayout, setName, setTarget, setStyle, setAttribute, unsetAttribute,'sendMessage'\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.updateLayout({}, {\n requestBody: {\n roomId: roomId,\n operation: operation,\n name: name,\n attributeName: attributeName,\n value: value,\n target: target\n }\n });\n });\n },\n getInviteUrl: function getInviteUrl(roomId, domain, url) {\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.invite({}, {\n requestBody: {\n roomId: roomId,\n domain: domain || location.host,\n url: url || location.href\n }\n });\n });\n },\n getRoomChatList: function getRoomChatList() {\n var _ref6 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n roomId = _ref6.roomId,\n _ref6$type = _ref6.type,\n type = _ref6$type === void 0 ? \"normal\" : _ref6$type,\n _ref6$size = _ref6.size,\n size = _ref6$size === void 0 ? 50 : _ref6$size,\n _ref6$startKey = _ref6.startKey,\n startKey = _ref6$startKey === void 0 ? null : _ref6$startKey;\n\n var apiParams = _objectSpread({\n roomId: roomId,\n type: type,\n size: size\n }, startKey && {\n startKey: startKey\n });\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.getRoomChatList(apiParams);\n });\n },\n getRoomsList: function getRoomsList() {\n var _ref7 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref7$type = _ref7.type,\n type = _ref7$type === void 0 ? 'participant' : _ref7$type,\n _ref7$activeOnly = _ref7.activeOnly,\n activeOnly = _ref7$activeOnly === void 0 ? null : _ref7$activeOnly,\n _ref7$instanceType = _ref7.instanceType,\n instanceType = _ref7$instanceType === void 0 ? _this.__instanceType : _ref7$instanceType,\n _ref7$size = _ref7.size,\n size = _ref7$size === void 0 ? 20 : _ref7$size,\n _ref7$startKey = _ref7.startKey,\n startKey = _ref7$startKey === void 0 ? null : _ref7$startKey,\n _ref7$includeWtEventM = _ref7.includeWtEventModels,\n includeWtEventModels = _ref7$includeWtEventM === void 0 ? false : _ref7$includeWtEventM,\n _ref7$demo = _ref7.demo,\n demo = _ref7$demo === void 0 ? false : _ref7$demo,\n _ref7$viewType = _ref7.viewType,\n viewType = _ref7$viewType === void 0 ? 'list' : _ref7$viewType,\n _ref7$wtChannelId = _ref7.wtChannelId,\n wtChannelId = _ref7$wtChannelId === void 0 ? undefined : _ref7$wtChannelId;\n\n var apiParams = _objectSpread(_objectSpread(_objectSpread({\n type: type,\n instanceType: instanceType,\n size: size,\n includeWtEventModels: includeWtEventModels,\n demo: demo,\n viewType: viewType\n }, wtChannelId && {\n wtChannelId: wtChannelId\n }), activeOnly && {\n activeOnly: activeOnly\n }), startKey && {\n startKey: startKey\n });\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.getRoomList(apiParams);\n });\n },\n setUser: function setUser(_ref8) {\n var messageId = _ref8.messageId,\n userId = _ref8.userId,\n roomId = _ref8.roomId,\n flag = _ref8.flag,\n timestamp = _ref8.timestamp,\n option = _ref8.option;\n //leave, kick, ban, unban, approve, report\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.setUser({\n messageId: messageId,\n userId: userId,\n roomId: roomId,\n flag: flag,\n timestamp: timestamp,\n option: option\n });\n });\n },\n getRoomById: function getRoomById(id) {\n var pinHash = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;\n var showPublic = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;\n var demo = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.getRoom({\n id: id,\n pinHash: pinHash,\n \"public\": showPublic,\n demo: demo\n });\n });\n },\n getRoomBySlug: function getRoomBySlug(slug) {\n var password = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;\n var showPublic = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;\n var demo = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.getRoom({\n slug: slug,\n password: password,\n \"public\": showPublic,\n demo: demo\n });\n });\n },\n roomRecorder: function roomRecorder() {\n var _ref9 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n roomId = _ref9.roomId,\n _ref9$operation = _ref9.operation,\n operation = _ref9$operation === void 0 ? 'get' : _ref9$operation,\n config = _ref9.config;\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.recordRoom({}, {\n requestBody: {\n roomId: roomId,\n operation: operation,\n config: config\n }\n });\n });\n },\n __joinRoom: function __joinRoom() {\n var _ref10 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n roomId = _ref10.roomId,\n pinHash = _ref10.pinHash,\n _ref10$instanceType = _ref10.instanceType,\n instanceType = _ref10$instanceType === void 0 ? _this.__instanceType : _ref10$instanceType,\n _ref10$isTalkback = _ref10.isTalkback,\n isTalkback = _ref10$isTalkback === void 0 ? undefined : _ref10$isTalkback,\n _ref10$isMonitor = _ref10.isMonitor,\n isMonitor = _ref10$isMonitor === void 0 ? undefined : _ref10$isMonitor,\n _ref10$isInstructor = _ref10.isInstructor,\n isInstructor = _ref10$isInstructor === void 0 ? undefined : _ref10$isInstructor,\n _ref10$customBearer = _ref10.customBearer,\n customBearer = _ref10$customBearer === void 0 ? undefined : _ref10$customBearer;\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.join({\n roomId: roomId,\n pinHash: pinHash,\n instanceType: instanceType,\n isTalkback: isTalkback,\n isMonitor: isMonitor,\n isInstructor: isInstructor,\n platform: _this.browser === 'firefox' ? 'web-firefox' : 'web'\n }, _objectSpread({}, customBearer ? {\n requestInterceptor: function requestInterceptor(req) {\n if (!req.headers) {\n req.headers = {};\n }\n\n req.headers['Authorization'] = customBearer;\n return req;\n }\n } : {}));\n });\n },\n isSafariSupported: function isSafariSupported() {\n return _this.__privates.room.safariVp8;\n },\n isWebrtcSupported: function isWebrtcSupported() {\n return _this.__privates.room.isWebrtcSupported;\n },\n createStreamingSession: function createStreamingSession() {\n var _ref11 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n constructId = _ref11.constructId,\n roomId = _ref11.roomId,\n pinHash = _ref11.pinHash,\n streamId = _ref11.streamId,\n href = _ref11.href,\n iceServers = _ref11.iceServers,\n accessToken = _ref11.accessToken;\n\n return _this.__privates.room.whenInitialized.then(function (lib) {\n return _streaming_session__WEBPACK_IMPORTED_MODULE_1__[\"default\"].call(_this, {\n roomId: roomId,\n pinHash: pinHash,\n streamId: streamId,\n href: href,\n iceServers: iceServers,\n accessToken: accessToken\n }, lib.createSession(constructId, 'streaming'), _this);\n }).then(function (newSession) {\n var existingSessionIndex = roomSessions.findIndex(function (session) {\n return session.constructId === newSession.constructId;\n });\n\n if (existingSessionIndex > -1) {\n return _this.room.destroySession(newSession.constructId).then(function () {\n roomSessions.push(newSession);\n return newSession;\n });\n } else {\n roomSessions.push(newSession);\n return newSession;\n }\n });\n },\n createSession: function createSession(_ref12) {\n var constructId = _ref12.constructId,\n roomId = _ref12.roomId,\n pinHash = _ref12.pinHash,\n isTalkback = _ref12.isTalkback,\n isMonitor = _ref12.isMonitor,\n isInstructor = _ref12.isInstructor,\n options = _ref12.options;\n return _this.__privates.room.whenInitialized.then(function (lib) {\n return _room_session__WEBPACK_IMPORTED_MODULE_0__[\"default\"].call(_this, {\n roomId: roomId,\n pinHash: pinHash,\n isTalkback: isTalkback,\n isMonitor: isMonitor,\n isInstructor: isInstructor\n }, lib.createSession(constructId, 'reactooroom', options), _this);\n }).then(function (newSession) {\n var existingSessionIndex = roomSessions.findIndex(function (session) {\n return session.constructId === newSession.constructId;\n });\n\n if (existingSessionIndex > -1) {\n return _this.room.destroySession(newSession.constructId).then(function () {\n roomSessions.push(newSession);\n return newSession;\n });\n } else {\n roomSessions.push(newSession);\n return newSession;\n }\n });\n },\n getSessions: function getSessions() {\n return roomSessions;\n },\n getSessionByConstructId: function getSessionByConstructId(constructId) {\n return roomSessions.find(function (session) {\n return session.constructId === constructId;\n }) || null;\n },\n getSessionBySessionId: function getSessionBySessionId(sessionId) {\n return roomSessions.find(function (session) {\n return session.sessionId === sessionId;\n }) || null;\n },\n getSessionByRoomId: function getSessionByRoomId(roomId) {\n return roomSessions.find(function (session) {\n return session.roomId === roomId;\n }) || null;\n },\n getSessionByUserId: function getSessionByUserId(userId) {\n return roomSessions.find(function (session) {\n return session.userId === userId;\n }) || null;\n },\n getSessionByStreamId: function getSessionByStreamId(streamId) {\n return roomSessions.find(function (session) {\n return session.streamId === streamId;\n }) || null;\n },\n destroySession: function destroySession(constructId) {\n var sessionIndex = roomSessions.findIndex(function (session) {\n return session.constructId === constructId;\n });\n\n if (sessionIndex > -1) {\n return roomSessions[sessionIndex].destroy().finally(function () {\n roomSessions.splice(sessionIndex, 1);\n return true;\n });\n }\n\n return Promise.resolve();\n },\n destroySessionBySessionId: function destroySessionBySessionId(sessionId) {\n var sessionIndex = roomSessions.findIndex(function (session) {\n return session.sessionId === sessionId;\n });\n\n if (sessionIndex > -1) {\n return roomSessions[sessionIndex].destroy().finally(function () {\n roomSessions.splice(sessionIndex, 1);\n return true;\n });\n }\n\n return Promise.resolve();\n },\n destroySessions: function destroySessions() {\n roomSessions.forEach(function (session) {\n return session.destroy().catch(function (e) {\n return _this.log(e);\n });\n });\n roomSessions.length = 0;\n },\n queue: function queue() {\n var _ref13 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n roomId = _ref13.roomId,\n operation = _ref13.operation,\n userId = _ref13.userId;\n\n //Enum: \"status\" \"join\" \"approve\" \"reject\" \"block\" \"unblock\"\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.queue({}, {\n requestBody: {\n roomId: roomId,\n operation: operation,\n userId: userId\n }\n });\n });\n },\n getDefaultRegions: function getDefaultRegions() {\n return _this.__privates.auth.__client.then(function (client) {\n var _client$spec, _client$spec$componen, _client$spec$componen2, _client$spec$componen3, _client$spec$componen4, _client$spec$componen5;\n\n return _toConsumableArray(((_client$spec = client.spec) === null || _client$spec === void 0 ? void 0 : (_client$spec$componen = _client$spec.components) === null || _client$spec$componen === void 0 ? void 0 : (_client$spec$componen2 = _client$spec$componen.schemas) === null || _client$spec$componen2 === void 0 ? void 0 : (_client$spec$componen3 = _client$spec$componen2.WtRoom) === null || _client$spec$componen3 === void 0 ? void 0 : (_client$spec$componen4 = _client$spec$componen3.properties) === null || _client$spec$componen4 === void 0 ? void 0 : (_client$spec$componen5 = _client$spec$componen4.defaultRegion) === null || _client$spec$componen5 === void 0 ? void 0 : _client$spec$componen5.enum) || ['']);\n });\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (room);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/room.js?");
9143
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _room_session__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./room-session */ \"./src/models/room-session.js\");\n/* harmony import */ var _streaming_session__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./streaming-session */ \"./src/models/streaming-session.js\");\n\n\n\n\n\nlet room = function () {\n var _this = this;\n\n let roomSessions = [];\n\n let setExitListeners = () => {\n window.addEventListener('pagehide', event => {\n if (!event.persisted) {\n this.room.destroySessions();\n }\n });\n window.addEventListener('beforeunload', () => {\n this.room.destroySessions();\n });\n };\n\n setExitListeners();\n return {\n //TODO: new model\n integration: function () {\n let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.system.integration({\n type: _this.__instanceType\n }, {\n requestBody: { ...data\n },\n requestInterceptor: req => {\n if (!req.headers) {\n req.headers = {};\n }\n\n req.headers['Authorization'] = 'Bearer ' + localStorage.getItem('rwt_idToken');\n return req;\n }\n }));\n },\n //TODO: new model\n getAnalytics: function () {\n let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.system.getAnalytics({\n instanceType: _this.__instanceType,\n ...data\n }));\n },\n sendChatMessage: _ref => {\n let {\n roomId,\n message,\n options,\n senderUserId\n } = _ref;\n return this.__privates.auth.__client.then(client => client.apis.wt.sendRoomMessage({}, {\n requestBody: {\n roomId,\n message,\n options,\n senderUserId\n }\n }));\n },\n createRoom: function () {\n let {\n title,\n description,\n isPublic,\n isListed,\n isStudioLayout,\n allowedParticipants,\n wtChannelId,\n isHd,\n disableSync,\n reduceRoomControls,\n muteParticipantOnJoin,\n hasStudioChat,\n maxParticipants,\n customAttributes\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.wt.createRoom({}, {\n requestBody: {\n title,\n description,\n isPublic,\n isListed,\n isStudioLayout,\n instanceType: _this.__instanceType,\n allowedParticipants,\n wtChannelId,\n isHd,\n disableSync,\n reduceRoomControls,\n muteParticipantOnJoin,\n hasStudioChat,\n maxParticipants,\n customAttributes\n }\n }));\n },\n updateRoom: function () {\n let {\n roomId,\n title,\n description,\n isPublic,\n isListed,\n allowedParticipants,\n recordings,\n slug,\n password,\n maxParticipants,\n setInstanceType = false,\n wtChannelId,\n isHd,\n isStudioLayout,\n hasStudioChat,\n reduceRoomControls,\n muteParticipantOnJoin,\n disableSync,\n defaultRegion,\n customAttributes,\n dotAttribute\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n let _da = dotAttribute ? Array.isArray(dotAttribute) ? dotAttribute.reduce((p, cv) => (p[cv.name] = cv.value) && p || p, {}) : {\n [dotAttribute.name]: dotAttribute.value\n } : {};\n\n return _this.__privates.auth.__client.then(client => client.apis.wt.updateRoom({\n id: roomId\n }, {\n requestBody: { ..._da,\n title,\n description,\n slug,\n password,\n isPublic,\n isListed,\n isHd,\n isStudioLayout,\n hasStudioChat,\n maxParticipants,\n reduceRoomControls,\n muteParticipantOnJoin,\n disableSync,\n defaultRegion,\n customAttributes,\n wtChannelId,\n ...(setInstanceType && {\n instanceType: setInstanceType === true ? _this.__instanceType : setInstanceType\n }),\n ...(allowedParticipants && {\n allowedParticipants\n }),\n ...(recordings && {\n recordings\n })\n }\n }));\n },\n deleteRoom: roomId => {\n return this.__privates.auth.__client.then(client => client.apis.wt.deleteRoom({\n id: roomId\n }));\n },\n leaveRoom: roomId => {\n return this.__privates.auth.__client.then(client => client.apis.wt.leave({\n roomId\n }));\n },\n updateLayout: _ref2 => {\n let {\n roomId,\n operation,\n name,\n attributeName,\n value,\n target\n } = _ref2;\n //operation : clearLayouts, setLayout, setLayouts, unsetLayout, setName, setTarget, setStyle, setAttribute, unsetAttribute,'sendMessage'\n return this.__privates.auth.__client.then(client => client.apis.wt.updateLayout({}, {\n requestBody: {\n roomId,\n operation,\n name,\n attributeName,\n value,\n target\n }\n }));\n },\n getInviteUrl: (roomId, domain, url) => {\n return this.__privates.auth.__client.then(client => client.apis.wt.invite({}, {\n requestBody: {\n roomId,\n domain: domain || location.host,\n url: url || location.href\n }\n }));\n },\n getRoomChatList: function () {\n let {\n roomId,\n type = \"normal\",\n size = 50,\n startKey = null\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let apiParams = {\n roomId,\n type,\n size,\n ...(startKey && {\n startKey\n })\n };\n return _this.__privates.auth.__client.then(client => client.apis.wt.getRoomChatList(apiParams));\n },\n getRoomsList: function () {\n let {\n type = 'participant',\n activeOnly = null,\n instanceType = _this.__instanceType,\n size = 20,\n startKey = null,\n includeWtEventModels = false,\n demo = false,\n viewType = 'list',\n wtChannelId = undefined\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let apiParams = {\n type,\n instanceType,\n size,\n includeWtEventModels,\n demo,\n viewType,\n ...(wtChannelId && {\n wtChannelId\n }),\n ...(activeOnly && {\n activeOnly\n }),\n ...(startKey && {\n startKey\n })\n };\n return _this.__privates.auth.__client.then(client => client.apis.wt.getRoomList(apiParams));\n },\n setUser: _ref3 => {\n let {\n messageId,\n userId,\n roomId,\n flag,\n timestamp,\n option\n } = _ref3;\n //leave, kick, ban, unban, approve, report\n return this.__privates.auth.__client.then(client => client.apis.wt.setUser({\n messageId,\n userId,\n roomId,\n flag,\n timestamp,\n option\n }));\n },\n getRoomById: function (id) {\n let pinHash = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;\n let showPublic = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;\n let demo = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n return _this.__privates.auth.__client.then(client => client.apis.wt.getRoom({\n id,\n pinHash,\n \"public\": showPublic,\n demo\n }));\n },\n getRoomBySlug: function (slug) {\n let password = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;\n let showPublic = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;\n let demo = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n return _this.__privates.auth.__client.then(client => client.apis.wt.getRoom({\n slug,\n password,\n \"public\": showPublic,\n demo\n }));\n },\n roomRecorder: function () {\n let {\n roomId,\n operation = 'get',\n config\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.wt.recordRoom({}, {\n requestBody: {\n roomId,\n operation,\n config\n }\n }));\n },\n __joinRoom: function () {\n let {\n roomId,\n pinHash,\n instanceType = _this.__instanceType,\n isTalkback = undefined,\n isMonitor = undefined,\n isInstructor = undefined,\n customBearer = undefined\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.wt.join({\n roomId,\n pinHash,\n instanceType,\n isTalkback,\n isMonitor,\n isInstructor,\n platform: _this.browser === 'firefox' ? 'web-firefox' : 'web'\n }, { ...(customBearer ? {\n requestInterceptor: req => {\n if (!req.headers) {\n req.headers = {};\n }\n\n req.headers['Authorization'] = customBearer;\n return req;\n }\n } : {})\n }));\n },\n isSafariSupported: () => {\n return this.__privates.room.safariVp8;\n },\n isWebrtcSupported: () => {\n return this.__privates.room.isWebrtcSupported;\n },\n createStreamingSession: function () {\n let {\n constructId,\n roomId,\n pinHash,\n streamId,\n href,\n iceServers,\n accessToken\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.room.whenInitialized.then(lib => _streaming_session__WEBPACK_IMPORTED_MODULE_1__[\"default\"].call(_this, {\n roomId,\n pinHash,\n streamId,\n href,\n iceServers,\n accessToken\n }, lib.createSession(constructId, 'streaming'), _this)).then(newSession => {\n let existingSessionIndex = roomSessions.findIndex(session => session.constructId === newSession.constructId);\n\n if (existingSessionIndex > -1) {\n return _this.room.destroySession(newSession.constructId).then(() => {\n roomSessions.push(newSession);\n return newSession;\n });\n } else {\n roomSessions.push(newSession);\n return newSession;\n }\n });\n },\n createSession: _ref4 => {\n let {\n constructId,\n roomId,\n pinHash,\n isTalkback,\n isMonitor,\n isInstructor,\n options\n } = _ref4;\n return this.__privates.room.whenInitialized.then(lib => _room_session__WEBPACK_IMPORTED_MODULE_0__[\"default\"].call(this, {\n roomId,\n pinHash,\n isTalkback,\n isMonitor,\n isInstructor\n }, lib.createSession(constructId, 'reactooroom', options), this)).then(newSession => {\n let existingSessionIndex = roomSessions.findIndex(session => session.constructId === newSession.constructId);\n\n if (existingSessionIndex > -1) {\n return this.room.destroySession(newSession.constructId).then(() => {\n roomSessions.push(newSession);\n return newSession;\n });\n } else {\n roomSessions.push(newSession);\n return newSession;\n }\n });\n },\n getSessions: () => {\n return roomSessions;\n },\n getSessionByConstructId: constructId => {\n return roomSessions.find(session => session.constructId === constructId) || null;\n },\n getSessionBySessionId: sessionId => {\n return roomSessions.find(session => session.sessionId === sessionId) || null;\n },\n getSessionByRoomId: roomId => {\n return roomSessions.find(session => session.roomId === roomId) || null;\n },\n getSessionByUserId: userId => {\n return roomSessions.find(session => session.userId === userId) || null;\n },\n getSessionByStreamId: streamId => {\n return roomSessions.find(session => session.streamId === streamId) || null;\n },\n destroySession: constructId => {\n let sessionIndex = roomSessions.findIndex(session => session.constructId === constructId);\n\n if (sessionIndex > -1) {\n return roomSessions[sessionIndex].destroy().finally(() => {\n roomSessions.splice(sessionIndex, 1);\n return true;\n });\n }\n\n return Promise.resolve();\n },\n destroySessionBySessionId: sessionId => {\n let sessionIndex = roomSessions.findIndex(session => session.sessionId === sessionId);\n\n if (sessionIndex > -1) {\n return roomSessions[sessionIndex].destroy().finally(() => {\n roomSessions.splice(sessionIndex, 1);\n return true;\n });\n }\n\n return Promise.resolve();\n },\n destroySessions: () => {\n roomSessions.forEach(session => session.destroy().catch(e => this.log(e)));\n roomSessions.length = 0;\n },\n queue: function () {\n let {\n roomId,\n operation,\n userId\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n //Enum: \"status\" \"join\" \"approve\" \"reject\" \"block\" \"unblock\"\n return _this.__privates.auth.__client.then(client => client.apis.wt.queue({}, {\n requestBody: {\n roomId,\n operation,\n userId\n }\n }));\n },\n getDefaultRegions: () => {\n return this.__privates.auth.__client.then(client => {\n var _client$spec, _client$spec$componen, _client$spec$componen2, _client$spec$componen3, _client$spec$componen4, _client$spec$componen5;\n\n return [...(((_client$spec = client.spec) === null || _client$spec === void 0 ? void 0 : (_client$spec$componen = _client$spec.components) === null || _client$spec$componen === void 0 ? void 0 : (_client$spec$componen2 = _client$spec$componen.schemas) === null || _client$spec$componen2 === void 0 ? void 0 : (_client$spec$componen3 = _client$spec$componen2.WtRoom) === null || _client$spec$componen3 === void 0 ? void 0 : (_client$spec$componen4 = _client$spec$componen3.properties) === null || _client$spec$componen4 === void 0 ? void 0 : (_client$spec$componen5 = _client$spec$componen4.defaultRegion) === null || _client$spec$componen5 === void 0 ? void 0 : _client$spec$componen5.enum) || [''])];\n });\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (room);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/room.js?");
9133
9144
 
9134
9145
  /***/ }),
9135
9146
 
@@ -9141,7 +9152,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _roo
9141
9152
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9142
9153
 
9143
9154
  "use strict";
9144
- eval("__webpack_require__.r(__webpack_exports__);\n\n\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\nfunction _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nvar streamingSession = function streamingSession() {\n var _this2 = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n roomId = _ref.roomId,\n pinHash = _ref.pinHash,\n streamId = _ref.streamId,\n href = _ref.href,\n iceServers = _ref.iceServers,\n accessToken = _ref.accessToken;\n\n var room = arguments.length > 1 ? arguments[1] : undefined;\n var wt = arguments.length > 2 ? arguments[2] : undefined;\n\n var ___;\n\n return ___ = {\n destroy: function destroy() {\n var _this = this;\n\n return wt.room.destroySession(room.constructId).finally(function () {\n _this.$clear();\n });\n },\n connect: function connect() {\n if (roomId) {\n return Promise.all([wt.room.getRoomById(roomId, pinHash), wt.user.getUserSelf()]).then(function (_ref2) {\n var _ref3 = _slicedToArray(_ref2, 2),\n roomData = _ref3[0],\n r = _ref3[1];\n\n return room.startStream(roomData.data.wtChannel.streamId, roomData.data.wtChannel.href, roomData.data.wtChannel.iceServers, roomData.data.wtChannel.accessToken, r.data._id);\n });\n } else if (href) {\n return wt.user.getUserSelf().then(function (r) {\n return room.startStream(streamId, href, iceServers, accessToken, r.data._id);\n });\n } else return Promise.reject('Bad Input');\n },\n disconnect: function disconnect() {\n return room.stopStream();\n },\n $on: function $on(key, callback, that) {\n return room.on(key, callback, that || _this2);\n },\n $off: function $off(key, callback, that) {\n return room.off(key, callback, that || _this2);\n },\n $clear: function $clear() {\n room.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (streamingSession);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/streaming-session.js?");
9155
+ eval("__webpack_require__.r(__webpack_exports__);\n\n\nlet streamingSession = function () {\n let {\n roomId,\n pinHash,\n streamId,\n href,\n iceServers,\n accessToken\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let room = arguments.length > 1 ? arguments[1] : undefined;\n let wt = arguments.length > 2 ? arguments[2] : undefined;\n\n let ___;\n\n return ___ = {\n destroy: function () {\n return wt.room.destroySession(room.constructId).finally(() => {\n this.$clear();\n });\n },\n connect: function () {\n if (roomId) {\n return Promise.all([wt.room.getRoomById(roomId, pinHash), wt.user.getUserSelf()]).then(_ref => {\n let [roomData, r] = _ref;\n return room.startStream(roomData.data.wtChannel.streamId, roomData.data.wtChannel.href, roomData.data.wtChannel.iceServers, roomData.data.wtChannel.accessToken, r.data._id);\n });\n } else if (href) {\n return wt.user.getUserSelf().then(r => room.startStream(streamId, href, iceServers, accessToken, r.data._id));\n } else return Promise.reject('Bad Input');\n },\n disconnect: function () {\n return room.stopStream();\n },\n $on: (key, callback, that) => {\n return room.on(key, callback, that || this);\n },\n $off: (key, callback, that) => {\n return room.off(key, callback, that || this);\n },\n $clear: function () {\n room.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (streamingSession);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/streaming-session.js?");
9145
9156
 
9146
9157
  /***/ }),
9147
9158
 
@@ -9153,7 +9164,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n\n\nfunction _slicedToArray(a
9153
9164
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9154
9165
 
9155
9166
  "use strict";
9156
- eval("__webpack_require__.r(__webpack_exports__);\n\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nvar system = function system() {\n var _this = this;\n\n return {\n integration: function integration() {\n var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.system.integration({\n type: _this.__instanceType\n }, {\n requestBody: _objectSpread({}, data),\n requestInterceptor: function requestInterceptor(req) {\n if (!req.headers) {\n req.headers = {};\n }\n\n req.headers['Authorization'] = 'Bearer ' + localStorage.getItem('rwt_idToken');\n return req;\n }\n });\n });\n },\n getAnalytics: function getAnalytics() {\n var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.system.getAnalytics(_objectSpread({\n instanceType: _this.__instanceType\n }, data));\n });\n },\n getTranslation: function getTranslation() {\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref$namespace = _ref.namespace,\n namespace = _ref$namespace === void 0 ? 'wt' : _ref$namespace;\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.system.getTranslation({\n namespace: namespace\n });\n });\n },\n getConfig: function getConfig() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref2$instanceType = _ref2.instanceType,\n instanceType = _ref2$instanceType === void 0 ? _this.__instanceType : _ref2$instanceType,\n _ref2$domain = _ref2.domain,\n domain = _ref2$domain === void 0 ? location.hostname : _ref2$domain;\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.system.getConfig({\n instanceType: instanceType,\n domain: domain\n });\n });\n },\n updateConfig: function updateConfig() {\n var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.system.updateConfig({\n id: data.instanceType || _this.__instanceType\n }, {\n requestBody: _objectSpread({}, data)\n });\n });\n },\n getIntegrationPublic: function getIntegrationPublic(type) {\n var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.system.integrationPublic({\n type: type\n }, {\n requestBody: _objectSpread({}, data)\n });\n });\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (system);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/system.js?");
9167
+ eval("__webpack_require__.r(__webpack_exports__);\n\n\nlet system = function () {\n var _this = this;\n\n return {\n integration: function () {\n let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.system.integration({\n type: _this.__instanceType\n }, {\n requestBody: { ...data\n },\n requestInterceptor: req => {\n if (!req.headers) {\n req.headers = {};\n }\n\n req.headers['Authorization'] = 'Bearer ' + localStorage.getItem('rwt_idToken');\n return req;\n }\n }));\n },\n getAnalytics: function () {\n let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.system.getAnalytics({\n instanceType: _this.__instanceType,\n ...data\n }));\n },\n getTranslation: function () {\n let {\n namespace = 'wt'\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.system.getTranslation({\n namespace\n }));\n },\n getConfig: function () {\n let {\n instanceType = _this.__instanceType,\n domain = location.hostname\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.system.getConfig({\n instanceType,\n domain\n }));\n },\n updateConfig: function () {\n let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.system.updateConfig({\n id: data.instanceType || _this.__instanceType\n }, {\n requestBody: { ...data\n }\n }));\n },\n getIntegrationPublic: function (type) {\n let data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n return _this.__privates.auth.__client.then(client => client.apis.system.integrationPublic({\n type\n }, {\n requestBody: { ...data\n }\n }));\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (system);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/system.js?");
9157
9168
 
9158
9169
  /***/ }),
9159
9170
 
@@ -9165,7 +9176,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n\n\nfunction ownKeys(object,
9165
9176
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9166
9177
 
9167
9178
  "use strict";
9168
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/wt-utils */ \"./src/modules/wt-utils.js\");\n/* harmony import */ var serialize_error__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! serialize-error */ \"./node_modules/serialize-error/index.js\");\n\n\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _iterableToArray(iter) { if (typeof Symbol !== \"undefined\" && iter[Symbol.iterator] != null || iter[\"@@iterator\"] != null) return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }\n\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\nfunction _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n\n\n\nvar user = function user() {\n var _this = this;\n\n return {\n updateUserSelf: function updateUserSelf() {\n var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.user.updateMyself(_objectSpread({}, data.lastRoomId && {\n lastRoomId: data.lastRoomId\n }), {\n requestBody: _objectSpread({}, data)\n });\n });\n },\n updateUser: function updateUser() {\n var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.user.updateUser(_objectSpread({}, data), {\n requestBody: _objectSpread({}, data)\n });\n });\n },\n uploadAvatar: function uploadAvatar(file, lastRoomId) {\n var id = Object(_modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"generateUUID\"])();\n return _this.__privates.auth.__client.then(function (client) {\n return Promise.all([client, client.apis.user.initiateMyAvatarUpload({\n id: id\n })]);\n }).then(function (_ref) {\n var _ref2 = _slicedToArray(_ref, 2),\n client = _ref2[0],\n response = _ref2[1];\n\n return Promise.all([client, client.http({\n url: response.data.signedUrl,\n method: response.data.httpMethod,\n headers: {\n \"Content-Type\": file.type\n },\n body: file\n })]);\n }).then(function (_ref3) {\n var _ref4 = _slicedToArray(_ref3, 2),\n client = _ref4[0],\n response = _ref4[1];\n\n return client.apis.user.publishMyAvatar({\n id: id,\n lastRoomId: lastRoomId\n });\n });\n },\n uploadReaction: function uploadReaction(files) {\n var id = Object(_modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"generateUUID\"])();\n return _this.__privates.auth.__client.then(function (client) {\n return Promise.all([client, client.apis.reaction.initiateReactionUpload({\n id: id,\n segmentCount: files.length || 0\n })]);\n }).then(function (_ref5) {\n var _ref6 = _slicedToArray(_ref5, 2),\n client = _ref6[0],\n response = _ref6[1];\n\n return Promise.all([client].concat(_toConsumableArray(response.data.signedUrlSegments.map(function (url, index) {\n return client.http({\n url: url,\n method: response.data.httpMethod,\n headers: {\n \"Content-Type\": files[index].type\n },\n body: files[index]\n });\n }))));\n }).then(function (_ref7) {\n var _ref8 = _slicedToArray(_ref7, 1),\n client = _ref8[0];\n\n return client.apis.reaction.processReaction({\n id: id,\n type: 'concat'\n });\n }).then(function (response) {\n return response.data.key;\n });\n },\n uploadVideo: function uploadVideo(roomId, files) {\n var privateAttributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n var id = Object(_modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"generateUUID\"])();\n return _this.__privates.auth.__client.then(function (client) {\n return Promise.all([client, client.apis.video.initiateVideoUpload({\n id: id,\n segmentCount: files.length || 0\n })]);\n }).then(function (_ref9) {\n var _ref10 = _slicedToArray(_ref9, 2),\n client = _ref10[0],\n response = _ref10[1];\n\n return Promise.all([client, response.data.signedUrlSegments.reduce(function (acc, url, index) {\n return acc.then(function () {\n return client.http({\n url: url,\n method: response.data.httpMethod,\n headers: {\n \"Content-Type\": files[index].type\n },\n body: files[index]\n });\n });\n }, Promise.resolve())]);\n }).then(function (_ref11) {\n var _ref12 = _slicedToArray(_ref11, 1),\n client = _ref12[0];\n\n return client.apis.video.publishVideo({\n _id: id,\n roomId: roomId\n }, {\n requestBody: {\n _id: id,\n roomId: roomId,\n privateAttributes: privateAttributes\n }\n });\n });\n },\n getReactionById: function getReactionById(id) {\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.reaction.getReactionById({\n id: id\n });\n });\n },\n getReactions: function getReactions() {\n var _ref13 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n userId = _ref13.userId,\n roomId = _ref13.roomId,\n type = _ref13.type,\n size = _ref13.size,\n startKey = _ref13.startKey,\n _ref13$includeUserMod = _ref13.includeUserModels,\n includeUserModels = _ref13$includeUserMod === void 0 ? false : _ref13$includeUserMod;\n\n var apiParams = _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({}, roomId && {\n roomId: roomId\n }), userId && {\n userId: userId\n }), size && {\n size: size\n }), startKey && {\n startKey: startKey\n }), {}, {\n includeUserModels: includeUserModels,\n type: type\n });\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.reaction.getReactions(apiParams);\n });\n },\n getVideoById: function getVideoById(id) {\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.video.getVideoById({\n id: id\n });\n });\n },\n getVideos: function getVideos() {\n var _ref14 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n roomId = _ref14.roomId,\n userId = _ref14.userId,\n type = _ref14.type,\n size = _ref14.size,\n startKey = _ref14.startKey,\n _ref14$includeUserMod = _ref14.includeUserModels,\n includeUserModels = _ref14$includeUserMod === void 0 ? false : _ref14$includeUserMod,\n includeRoomQueueStatus = _ref14.includeRoomQueueStatus;\n\n var apiParams = _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({}, roomId && {\n roomId: roomId\n }), userId && {\n userId: userId\n }), size && {\n size: size\n }), startKey && {\n startKey: startKey\n }), includeRoomQueueStatus && {\n includeRoomQueueStatus: includeRoomQueueStatus\n }), {}, {\n includeUserModels: includeUserModels,\n type: type\n });\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.video.getVideos(apiParams);\n });\n },\n getUserSelf: function getUserSelf() {\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.user.getUserMyself();\n });\n },\n getUserById: function getUserById(id) {\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.user.getUserById({\n id: id\n });\n });\n },\n getUsersByIds: function getUsersByIds() {\n var _ref15 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref15$ids = _ref15.ids,\n ids = _ref15$ids === void 0 ? [] : _ref15$ids,\n _ref15$size = _ref15.size,\n size = _ref15$size === void 0 ? null : _ref15$size,\n _ref15$startKey = _ref15.startKey,\n startKey = _ref15$startKey === void 0 ? null : _ref15$startKey;\n\n var apiParams = _objectSpread(_objectSpread(_objectSpread({\n type: 'ids'\n }, size && {\n size: size\n }), ids && {\n ids: ids.join(',')\n }), startKey && {\n startKey: startKey\n });\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.user.getUsers(apiParams);\n });\n },\n getUsers: function getUsers() {\n var _ref16 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n type = _ref16.type,\n userId = _ref16.userId,\n roomId = _ref16.roomId,\n _ref16$size = _ref16.size,\n size = _ref16$size === void 0 ? 20 : _ref16$size,\n _ref16$startKey = _ref16.startKey,\n startKey = _ref16$startKey === void 0 ? null : _ref16$startKey;\n\n var apiParams = _objectSpread(_objectSpread(_objectSpread({\n type: type,\n size: size\n }, roomId && {\n roomId: roomId\n }), userId && {\n userId: userId\n }), startKey && {\n startKey: startKey\n });\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.user.getUsers(apiParams);\n });\n },\n //TODO: should have own model\n track: function track() {\n var _ref17 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref17$eventType = _ref17.eventType,\n eventType = _ref17$eventType === void 0 ? 'ERROR' : _ref17$eventType,\n message = _ref17.message;\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.track({}, {\n requestBody: {\n \"eventType\": eventType,\n \"appType\": \"web\",\n \"deviceType\": \"desktop\".concat(navigator.maxTouchPoints ? '/touch' : ''),\n \"os\": navigator.platform,\n \"browser\": navigator.userAgent,\n \"domain\": location.host,\n \"url\": location.href,\n \"message\": Object(serialize_error__WEBPACK_IMPORTED_MODULE_1__[\"serializeError\"])(message)\n }\n });\n });\n },\n //TODO: new model\n getTranslation: function getTranslation() {\n var _ref18 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref18$namespace = _ref18.namespace,\n namespace = _ref18$namespace === void 0 ? 'wt' : _ref18$namespace;\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.system.getTranslation({\n namespace: namespace\n });\n });\n },\n //TODO: new model\n getConfig: function getConfig() {\n var _ref19 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref19$instanceType = _ref19.instanceType,\n instanceType = _ref19$instanceType === void 0 ? _this.__instanceType : _ref19$instanceType,\n _ref19$domain = _ref19.domain,\n domain = _ref19$domain === void 0 ? location.hostname : _ref19$domain;\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.system.getConfig({\n instanceType: instanceType,\n domain: domain\n });\n });\n },\n //TODO: new model\n getIntegrationPublic: function getIntegrationPublic(type) {\n var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.system.integrationPublic({\n type: type\n }, {\n requestBody: _objectSpread({}, data)\n });\n });\n },\n updateConfig: function updateConfig() {\n var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.updateConfig({\n id: data.instanceType || _this.__instanceType\n }, {\n requestBody: _objectSpread({}, data)\n });\n });\n },\n admin: function admin() {\n var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.admin({}, {\n requestBody: _objectSpread({\n instanceType: _this.__instanceType\n }, data)\n });\n });\n },\n analytics: function analytics() {\n var _ref20 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n action = _ref20.action,\n _ref20$startKey = _ref20.startKey,\n startKey = _ref20$startKey === void 0 ? null : _ref20$startKey,\n _ref20$limit = _ref20.limit,\n limit = _ref20$limit === void 0 ? 20 : _ref20$limit;\n\n var apiParams = _objectSpread({\n action: action,\n limit: limit\n }, startKey && {\n startKey: startKey\n });\n\n return _this.__privates.auth.__client.then(function (client) {\n return client.apis.wt.analytics({}, {\n requestBody: _objectSpread({\n instanceType: _this.__instanceType\n }, apiParams)\n });\n });\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (user);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/user.js?");
9179
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/wt-utils */ \"./src/modules/wt-utils.js\");\n/* harmony import */ var serialize_error__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! serialize-error */ \"./node_modules/serialize-error/index.js\");\n\n\n\n\n\nlet user = function () {\n var _this = this;\n\n return {\n updateUserSelf: function () {\n let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.user.updateMyself({ ...(data.lastRoomId && {\n lastRoomId: data.lastRoomId\n })\n }, {\n requestBody: { ...data\n }\n }));\n },\n updateUser: function () {\n let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.user.updateUser({ ...data\n }, {\n requestBody: { ...data\n }\n }));\n },\n uploadAvatar: (file, lastRoomId) => {\n let id = Object(_modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"generateUUID\"])();\n return this.__privates.auth.__client.then(client => Promise.all([client, client.apis.user.initiateMyAvatarUpload({\n id\n })])).then(_ref => {\n let [client, response] = _ref;\n return Promise.all([client, client.http({\n url: response.data.signedUrl,\n method: response.data.httpMethod,\n headers: {\n \"Content-Type\": file.type\n },\n body: file\n })]);\n }).then(_ref2 => {\n let [client, response] = _ref2;\n return client.apis.user.publishMyAvatar({\n id,\n lastRoomId\n });\n });\n },\n uploadReaction: files => {\n let id = Object(_modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"generateUUID\"])();\n return this.__privates.auth.__client.then(client => Promise.all([client, client.apis.reaction.initiateReactionUpload({\n id: id,\n segmentCount: files.length || 0\n })])).then(_ref3 => {\n let [client, response] = _ref3;\n return Promise.all([client, ...response.data.signedUrlSegments.map((url, index) => client.http({\n url,\n method: response.data.httpMethod,\n headers: {\n \"Content-Type\": files[index].type\n },\n body: files[index]\n }))]);\n }).then(_ref4 => {\n let [client] = _ref4;\n return client.apis.reaction.processReaction({\n id: id,\n type: 'concat'\n });\n }).then(response => response.data.key);\n },\n uploadVideo: function (roomId, files) {\n let privateAttributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n let id = Object(_modules_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"generateUUID\"])();\n return _this.__privates.auth.__client.then(client => Promise.all([client, client.apis.video.initiateVideoUpload({\n id,\n segmentCount: files.length || 0\n })])).then(_ref5 => {\n let [client, response] = _ref5;\n return Promise.all([client, response.data.signedUrlSegments.reduce((acc, url, index) => acc.then(() => client.http({\n url,\n method: response.data.httpMethod,\n headers: {\n \"Content-Type\": files[index].type\n },\n body: files[index]\n })), Promise.resolve())]);\n }).then(_ref6 => {\n let [client] = _ref6;\n return client.apis.video.publishVideo({\n _id: id,\n roomId\n }, {\n requestBody: {\n _id: id,\n roomId,\n privateAttributes\n }\n });\n });\n },\n getReactionById: id => {\n return this.__privates.auth.__client.then(client => client.apis.reaction.getReactionById({\n id\n }));\n },\n getReactions: function () {\n let {\n userId,\n roomId,\n type,\n size,\n startKey,\n includeUserModels = false\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let apiParams = { ...(roomId && {\n roomId\n }),\n ...(userId && {\n userId\n }),\n ...(size && {\n size\n }),\n ...(startKey && {\n startKey\n }),\n includeUserModels,\n type\n };\n return _this.__privates.auth.__client.then(client => client.apis.reaction.getReactions(apiParams));\n },\n getVideoById: id => {\n return this.__privates.auth.__client.then(client => client.apis.video.getVideoById({\n id\n }));\n },\n getVideos: function () {\n let {\n roomId,\n userId,\n type,\n size,\n startKey,\n includeUserModels = false,\n includeRoomQueueStatus\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let apiParams = { ...(roomId && {\n roomId\n }),\n ...(userId && {\n userId\n }),\n ...(size && {\n size\n }),\n ...(startKey && {\n startKey\n }),\n ...(includeRoomQueueStatus && {\n includeRoomQueueStatus\n }),\n includeUserModels,\n type\n };\n return _this.__privates.auth.__client.then(client => client.apis.video.getVideos(apiParams));\n },\n getUserSelf: () => {\n return this.__privates.auth.__client.then(client => client.apis.user.getUserMyself());\n },\n getUserById: id => {\n return this.__privates.auth.__client.then(client => client.apis.user.getUserById({\n id\n }));\n },\n getUsersByIds: function () {\n let {\n ids = [],\n size = null,\n startKey = null\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let apiParams = {\n type: 'ids',\n ...(size && {\n size\n }),\n ...(ids && {\n ids: ids.join(',')\n }),\n ...(startKey && {\n startKey\n })\n };\n return _this.__privates.auth.__client.then(client => client.apis.user.getUsers(apiParams));\n },\n getUsers: function () {\n let {\n type,\n userId,\n roomId,\n size = 20,\n startKey = null\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let apiParams = {\n type,\n size,\n ...(roomId && {\n roomId\n }),\n ...(userId && {\n userId\n }),\n ...(startKey && {\n startKey\n })\n };\n return _this.__privates.auth.__client.then(client => client.apis.user.getUsers(apiParams));\n },\n //TODO: should have own model\n track: function () {\n let {\n eventType = 'ERROR',\n message\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.wt.track({}, {\n requestBody: {\n \"eventType\": eventType,\n \"appType\": \"web\",\n \"deviceType\": \"desktop\".concat(navigator.maxTouchPoints ? '/touch' : ''),\n \"os\": navigator.platform,\n \"browser\": navigator.userAgent,\n \"domain\": location.host,\n \"url\": location.href,\n \"message\": Object(serialize_error__WEBPACK_IMPORTED_MODULE_1__[\"serializeError\"])(message)\n }\n }));\n },\n //TODO: new model\n getTranslation: function () {\n let {\n namespace = 'wt'\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.system.getTranslation({\n namespace\n }));\n },\n //TODO: new model\n getConfig: function () {\n let {\n instanceType = _this.__instanceType,\n domain = location.hostname\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.system.getConfig({\n instanceType,\n domain\n }));\n },\n //TODO: new model\n getIntegrationPublic: function (type) {\n let data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n return _this.__privates.auth.__client.then(client => client.apis.system.integrationPublic({\n type\n }, {\n requestBody: { ...data\n }\n }));\n },\n updateConfig: function () {\n let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.wt.updateConfig({\n id: data.instanceType || _this.__instanceType\n }, {\n requestBody: { ...data\n }\n }));\n },\n admin: function () {\n let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return _this.__privates.auth.__client.then(client => client.apis.wt.admin({}, {\n requestBody: {\n instanceType: _this.__instanceType,\n ...data\n }\n }));\n },\n analytics: function () {\n let {\n action,\n startKey = null,\n limit = 20\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let apiParams = {\n action,\n limit,\n ...(startKey && {\n startKey\n })\n };\n return _this.__privates.auth.__client.then(client => client.apis.wt.analytics({}, {\n requestBody: {\n instanceType: _this.__instanceType,\n ...apiParams\n }\n }));\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (user);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/user.js?");
9169
9180
 
9170
9181
  /***/ }),
9171
9182
 
@@ -9177,7 +9188,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _mod
9177
9188
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9178
9189
 
9179
9190
  "use strict";
9180
- eval("__webpack_require__.r(__webpack_exports__);\n\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n getUserStream: function getUserStream() {\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n hasVideo = _ref.hasVideo,\n isHd = _ref.isHd,\n aDeviceId = _ref.aDeviceId,\n vDeviceId = _ref.vDeviceId,\n lfps = _ref.lfps,\n _ref$autoGainControl = _ref.autoGainControl,\n autoGainControl = _ref$autoGainControl === void 0 ? false : _ref$autoGainControl,\n _ref$muteAudio = _ref.muteAudio,\n muteAudio = _ref$muteAudio === void 0 ? false : _ref$muteAudio,\n _ref$muteVideo = _ref.muteVideo,\n muteVideo = _ref$muteVideo === void 0 ? false : _ref$muteVideo;\n\n var fullConstraints = {\n audio: _objectSpread(_objectSpread({}, aDeviceId && {\n deviceId: {\n exact: aDeviceId\n }\n }), {}, {\n autoGainControl: autoGainControl,\n echoCancellation: true,\n noiseSuppression: true,\n channelCount: 1\n }),\n video: _objectSpread(_objectSpread(_objectSpread({}, vDeviceId && {\n deviceId: {\n exact: vDeviceId\n }\n }), {}, {\n facingMode: {\n ideal: \"user\"\n }\n }, lfps ? {\n frameRate: {\n ideal: 10,\n max: 30\n }\n } : {\n frameRate: {\n ideal: 24,\n max: 30\n }\n }), {}, {\n width: {\n ideal: isHd ? 1280 : 320\n },\n height: {\n ideal: isHd ? 720 : 240\n }\n })\n };\n var audioOnlyConstraints = {\n audio: _objectSpread(_objectSpread({}, aDeviceId && {\n deviceId: {\n exact: aDeviceId\n }\n }), {}, {\n autoGainControl: autoGainControl,\n echoCancellation: true,\n noiseSuppression: true,\n channelCount: 1\n })\n };\n return navigator.mediaDevices.getUserMedia(hasVideo ? fullConstraints : audioOnlyConstraints).then(function (stream) {\n if (muteAudio) {\n stream.getAudioTracks().forEach(function (track) {\n return track.enabled = false;\n });\n }\n\n if (muteVideo) {\n stream.getVideoTracks().forEach(function (track) {\n return track.enabled = false;\n });\n }\n\n return stream;\n });\n }\n});\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/utils.js?");
9191
+ eval("__webpack_require__.r(__webpack_exports__);\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n getUserStream() {\n let {\n hasVideo,\n isHd,\n aDeviceId,\n vDeviceId,\n lfps,\n autoGainControl = false,\n muteAudio = false,\n muteVideo = false\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let fullConstraints = {\n audio: { ...(aDeviceId && {\n deviceId: {\n exact: aDeviceId\n }\n }),\n autoGainControl,\n echoCancellation: true,\n noiseSuppression: true,\n channelCount: 1\n },\n video: { ...(vDeviceId && {\n deviceId: {\n exact: vDeviceId\n }\n }),\n facingMode: {\n ideal: \"user\"\n },\n ...(lfps ? {\n frameRate: {\n ideal: 10,\n max: 30\n }\n } : {\n frameRate: {\n ideal: 24,\n max: 30\n }\n }),\n width: {\n ideal: isHd ? 1280 : 320\n },\n height: {\n ideal: isHd ? 720 : 240\n }\n }\n };\n let audioOnlyConstraints = {\n audio: { ...(aDeviceId && {\n deviceId: {\n exact: aDeviceId\n }\n }),\n autoGainControl,\n echoCancellation: true,\n noiseSuppression: true,\n channelCount: 1\n }\n };\n return navigator.mediaDevices.getUserMedia(hasVideo ? fullConstraints : audioOnlyConstraints).then(stream => {\n if (muteAudio) {\n stream.getAudioTracks().forEach(track => track.enabled = false);\n }\n\n if (muteVideo) {\n stream.getVideoTracks().forEach(track => track.enabled = false);\n }\n\n return stream;\n });\n }\n\n});\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/models/utils.js?");
9181
9192
 
9182
9193
  /***/ }),
9183
9194
 
@@ -9189,7 +9200,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n\n\nfunction ownKeys(object,
9189
9200
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9190
9201
 
9191
9202
  "use strict";
9192
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n\n\nvar syncVodDashJs = function syncVodDashJs() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var _roomId = null;\n var _syncDisabled = false;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var seekingDebounceId = null;\n var seekingDebounceTimeout = 300;\n var isPlaying = false;\n var isProgrammaticallySeeked = false;\n var isForcedMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (_syncDisabled) {\n room._log('--- Sync loop will not start due to sync force disabled ---');\n\n return;\n }\n\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (syncData.masterFragmentSn) {\n playMedia();\n } else {\n pauseMedia();\n }\n\n if (position && Math.abs(position - currentPosition) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(position + (isPlaying ? seekDuration : 0) - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement) {\n //TODO: shit fix ... data channel with other participant is not opened yet so we wait\n setTimeout(function () {\n restartSyncLoop();\n }, 1000);\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var handleRemoveRemoteParticipant = function handleRemoveRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var buffering = function buffering(event) {\n if (event.mediaType === 'video' || event.mediaType === 'audio') {\n if (event.state === 'bufferStalled') {\n handleStalledWaiting();\n }\n }\n };\n\n var executePlayerIotEvents = function executePlayerIotEvents(data) {\n var rid = _roomId || room.roomId;\n\n if (data.attributeName === 'playerReplay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n seekTo(0).then(function () {\n return playMedia();\n });\n }\n\n if (data.attributeName === 'playerPlay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n playMedia();\n }\n\n if (data.attributeName === 'playerPause' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n pauseMedia();\n }\n };\n\n var parseIotEvents = function parseIotEvents(data) {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(function (event) {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents(_objectSpread(_objectSpread({}, event), {}, {\n roomId: data.roomId,\n userId: data.userId\n }));\n }\n });\n }\n\n if (data.operation === 'sendMessage') {\n executePlayerIotEvents(data);\n }\n }\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n } else if (msg.videoroom === 'message') {\n // ignoring non studio commands if master\n if (isForcedMaster && msg.from !== null) {\n return;\n }\n\n if (_syncDisabled) {\n return;\n }\n\n if (msg.user_action === 'sync_seeking') {\n seekMedia(msg).catch(function () {});\n } else if (msg.user_action === 'sync_seeked') {} else if (msg.user_action === 'sync_play' || msg.action === 'sync_play') {\n playMedia();\n } else if (msg.user_action === 'sync_pause' || msg.action === 'sync_pause') {\n pauseMedia();\n }\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn) {\n var fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n var seekMedia = function seekMedia(msg) {\n msg = _objectSpread({\n userId: msg.from\n }, msg.text && JSON.parse(msg.text));\n\n if (msg.handleId !== room.handleId) {\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0),\n position = _calculateSyncDiffere2.position,\n isBufferSufficient = _calculateSyncDiffere2.isBufferSufficient; //TODO: right ping\n\n\n if (position) {\n return seekTo(position).then(function () {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n var prePlay = function prePlay() {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n var wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(function () {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(function () {\n return true;\n }).finally(function () {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n var playMedia = function playMedia() {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(function () {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n var pauseMedia = function pauseMedia() {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', function () {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve) {\n if (_videoElement.currentTime !== time) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('seeked', function () {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(function () {});\n }\n };\n\n var handleSeeking = function handleSeeking() {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(function () {\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n roomSession.sendSystemMessage('sync_seeking', {\n timestamp: new Date().getTime(),\n handleId: room.handleId,\n fragment: \"0\",\n //isPlaying ? \"1\":\"0\",\n fragment_pos: Number(fragmentPosition)\n }, undefined, null).catch(function () {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n var handleSeeked = function handleSeeked() {};\n\n var handleEnded = function handleEnded() {};\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\n room._log(\"I've been asked for position even if we don't have player attached.\\n Does it mean I'm the master?\");\n\n return Promise.resolve();\n }\n\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function fn(msg) {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, _this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, _this);\n room.sendMessage(room.handleId, {\n body: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function clientPaused() {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n var propagateMasterFunc = function propagateMasterFunc() {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n dashInstance = _ref2.dashInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster,\n _ref2$isStudio = _ref2.isStudio,\n isStudio = _ref2$isStudio === void 0 ? false : _ref2$isStudio,\n roomId = _ref2.roomId,\n syncDisabled = _ref2.syncDisabled;\n\n _libraryInstance = dashInstance || libraryInstance;\n _videoElement = _libraryInstance.getVideoElement();\n _roomId = roomId;\n _syncDisabled = syncDisabled;\n\n if (!_libraryInstance) {\n console.log('No player instance');\n return;\n }\n\n emitter.emit('playerSyncing', false);\n isForcedMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.on('data', parseDataEvents);\n wt.iot.$on('message', parseIotEvents);\n\n if (isForcedMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_libraryInstance && _videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(function () {\n _libraryInstance.on('bufferStateChanged', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n\n _videoElement.addEventListener('seeking', handleSeeking);\n\n _videoElement.addEventListener('seeked', handleSeeked);\n\n _videoElement.addEventListener('ended', handleEnded);\n\n startSyncLoop();\n });\n }\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_libraryInstance) {\n _libraryInstance.off('bufferStateChanged', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _libraryInstance = null;\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodDashJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-dash-vod.js?");
9203
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nconst syncVodDashJs = function () {\n let {\n room,\n wt,\n roomSession,\n emitter\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n //SYNC VARS\n let _libraryInstance = null;\n let _videoElement = null;\n let _roomId = null;\n let _syncDisabled = false;\n const syncDefaultWaitTime = 60000;\n const syncShortWaitTime = 10000;\n const maxSyncThreshold = 0.5;\n const maxSyncTries = 3;\n let currentSyncRetry = 0;\n let syncWaitId = null;\n let syncNextWaitTime = null;\n let stopFlag = false;\n let isSyncing = false;\n let seekingDebounceId = null;\n let seekingDebounceTimeout = 300;\n let isPlaying = false;\n let isProgrammaticallySeeked = false;\n let isForcedMaster = false;\n\n const 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 const loop = () => {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(() => {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n const stopSyncLoop = () => {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n const restartSyncLoop = () => {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n const setNextWaitTime = function () {\n let didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n const sync = () => {\n return getSyncData().then(syncData => {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n const syncStartTime = Date.now();\n const {\n position,\n isBufferSufficient\n } = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping);\n const 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(() => {\n const seekDuration = (Date.now() - syncStartTime) / 1000;\n const 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 const didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(e => {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(() => {\n setNextWaitTime(true);\n });\n };\n\n const 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(() => {\n restartSyncLoop();\n }, 1000);\n }\n };\n\n const handleAddRemoteParticipant = () => {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n const handleRemoveRemoteParticipant = () => {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n const isConnected = () => {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n const buffering = event => {\n if (event.mediaType === 'video' || event.mediaType === 'audio') {\n if (event.state === 'bufferStalled') {\n handleStalledWaiting();\n }\n }\n };\n\n const executePlayerIotEvents = data => {\n let 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(() => playMedia());\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 const parseIotEvents = data => {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(event => {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents({ ...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 const parseDataEvents = function () {\n let 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(() => {});\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(() => {});\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 const getCurrentSegmentPosition = () => {\n let position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n const calculateSyncDifferenceTime = function (fragmentSn) {\n let fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n let ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n const seekMedia = msg => {\n msg = {\n userId: msg.from,\n ...(msg.text && JSON.parse(msg.text))\n };\n\n if (msg.handleId !== room.handleId) {\n const {\n position,\n isBufferSufficient\n } = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0); //TODO: right ping\n\n if (position) {\n return seekTo(position).then(() => {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n const prePlay = () => {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n let wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(() => {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(() => true).finally(() => {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n const playMedia = () => {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(() => {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n const pauseMedia = () => {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', () => {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n const seekTo = time => {\n return new Promise(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', () => {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n const handlePlaying = () => {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(() => {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n const handlePause = () => {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(() => {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n const handleStalledWaiting = () => {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(() => {});\n }\n };\n\n const handleSeeking = () => {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(() => {\n let 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(() => {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n const handleSeeked = () => {};\n\n const handleEnded = () => {};\n\n const 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 let fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n const getSyncData = () => {\n room._log('Sending roomSync request');\n\n let roomId = room.roomId;\n let fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise((resolve, reject) => {\n let now = new Date().getTime();\n let ping = null;\n let sid = setTimeout(() => {\n room.off('data', fn, this);\n reject('Timeout');\n }, 3000);\n let body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n let fn = msg => {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, this);\n room.sendMessage(room.handleId, {\n body\n }).then(fn).catch(e => {\n room.off('data', fn, this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n const clientPaused = () => {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n const propagateMasterFunc = () => {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function () {\n let {\n dashInstance,\n libraryInstance,\n propagateMaster = false,\n isStudio = false,\n roomId,\n syncDisabled\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\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(() => {});\n }\n\n if (_libraryInstance && _videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(() => {\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: () => {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_libraryInstance) {\n _libraryInstance.off('bufferStateChanged', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _libraryInstance = null;\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodDashJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-dash-vod.js?");
9193
9204
 
9194
9205
  /***/ }),
9195
9206
 
@@ -9201,7 +9212,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9201
9212
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9202
9213
 
9203
9214
  "use strict";
9204
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nvar syncDashJs = function syncDashJs() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n realPosition = _calculateSyncDiffere.realPosition,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var buffering = function buffering(event) {\n if (event.mediaType === 'video' || event.mediaType === 'audio') {\n if (event.state === 'bufferStalled') {\n handleStalledWaiting();\n }\n }\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos, ping) {\n var seekRanges = _videoElement.buffered;\n var seekRange = {};\n\n for (var i = 0; i < seekRanges.length; i++) {\n var _c_start = seekRanges.start(i);\n\n var _c_end = seekRanges.end(i);\n\n if (!seekRange.start || _c_start < seekRange.start) {\n seekRange.start = _c_start;\n }\n\n if (!seekRange.end || _c_end > seekRange.end) {\n seekRange.end = _c_end;\n }\n }\n\n var position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position: position,\n realPosition: position,\n isBufferSufficient: true\n };\n } else if (position < seekRange.start) {\n room._log(\"Syncing to \".concat(seekRange.start, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.start + 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else if (position > seekRange.end) {\n room._log(\"Syncing to \".concat(seekRange.end, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.end - 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPosition: position,\n isBufferSufficient: false\n };\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve, reject) {\n if (_videoElement.currentTime !== time) {\n var diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\n room._log(\"I've been asked for position even if we don't have player attached.\\n Does it mean I'm the master?\");\n\n return Promise.resolve();\n }\n\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function fn(msg) {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, _this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, _this);\n room.sendMessage(room.handleId, {\n body: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function clientPaused() {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n var propagateMasterFunc = function propagateMasterFunc() {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n dashInstance = _ref2.dashInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _libraryInstance = dashInstance || libraryInstance; // backwards comp;\n\n _videoElement = _libraryInstance.getVideoElement();\n\n if (!_libraryInstance) {\n room._log('No dash player instance!');\n\n return;\n }\n\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _libraryInstance.on('bufferStateChanged', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n\n if (_libraryInstance) {\n _libraryInstance.off('bufferStateChanged', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDashJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-dash.js?");
9215
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nconst syncDashJs = function () {\n let {\n room,\n wt,\n roomSession,\n emitter\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n //SYNC VARS\n let _libraryInstance = null;\n let _videoElement = null;\n const syncDefaultWaitTime = 60000;\n const syncShortWaitTime = 10000;\n const maxSyncThreshold = 0.5;\n const maxSyncTries = 3;\n let currentSyncRetry = 0;\n let syncWaitId = null;\n let syncNextWaitTime = null;\n let stopFlag = false;\n let isSyncing = false;\n let playbackRate = 2;\n let isPlaying = false;\n let isPreloading = true;\n let isProgrammaticallySeeked = false;\n let shouldPropagateMaster = false;\n\n const startSyncLoop = () => {\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n const loop = () => {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(() => {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n const stopSyncLoop = () => {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n const restartSyncLoop = () => {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n const setNextWaitTime = function () {\n let didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n const sync = () => {\n return getSyncData().then(syncData => {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n const syncStartTime = Date.now();\n const {\n position,\n realPosition,\n isBufferSufficient\n } = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping);\n const currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekTo(position).then(() => {\n const seekDuration = (Date.now() - syncStartTime) / 1000;\n const syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n const didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(e => {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(() => {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n const handleAddLocalParticipant = () => {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', () => {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n const handleAddRemoteParticipant = () => {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n const isConnected = () => {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n const buffering = event => {\n if (event.mediaType === 'video' || event.mediaType === 'audio') {\n if (event.state === 'bufferStalled') {\n handleStalledWaiting();\n }\n }\n };\n\n const parseDataEvents = function () {\n let 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(() => {});\n }\n };\n\n const getCurrentSegmentPosition = () => {\n let position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n const calculateSyncDifferenceTime = (fragmentSn, fragmentPos, ping) => {\n let seekRanges = _videoElement.buffered;\n let seekRange = {};\n\n for (let i = 0; i < seekRanges.length; i++) {\n let _c_start = seekRanges.start(i);\n\n let _c_end = seekRanges.end(i);\n\n if (!seekRange.start || _c_start < seekRange.start) {\n seekRange.start = _c_start;\n }\n\n if (!seekRange.end || _c_end > seekRange.end) {\n seekRange.end = _c_end;\n }\n }\n\n let position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position,\n realPosition: position,\n isBufferSufficient: true\n };\n } else if (position < seekRange.start) {\n room._log(\"Syncing to \".concat(seekRange.start, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.start + 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else if (position > seekRange.end) {\n room._log(\"Syncing to \".concat(seekRange.end, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.end - 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPosition: position,\n isBufferSufficient: false\n };\n };\n\n const seekTo = time => {\n return new Promise((resolve, reject) => {\n if (_videoElement.currentTime !== time) {\n let diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n let wasPaused = false;\n\n let __ = () => {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(() => {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(() => {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n let __ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', () => {\n room._log(\"It took the player \".concat((Date.now() - __) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n };\n\n const handlePlaying = () => {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n const handlePause = () => {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPlaying = !_videoElement.paused;\n };\n\n const handleStalledWaiting = () => {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPreloading = _videoElement.paused;\n }\n };\n\n const 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 let fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n const getSyncData = () => {\n room._log('Sending roomSync request');\n\n let roomId = room.roomId;\n let fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise((resolve, reject) => {\n let now = new Date().getTime();\n let ping = null;\n let sid = setTimeout(() => {\n room.off('data', fn, this);\n reject('Timeout');\n }, 3000);\n let body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n let fn = msg => {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, this);\n room.sendMessage(room.handleId, {\n body\n }).then(fn).catch(e => {\n room.off('data', fn, this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n const clientPaused = () => {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n const propagateMasterFunc = () => {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function () {\n let {\n dashInstance,\n libraryInstance,\n propagateMaster = false\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _libraryInstance = dashInstance || libraryInstance; // backwards comp;\n\n _videoElement = _libraryInstance.getVideoElement();\n\n if (!_libraryInstance) {\n room._log('No dash player instance!');\n\n return;\n }\n\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (shouldPropagateMaster) {\n propagateMasterFunc().catch(() => {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', () => {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _libraryInstance.on('bufferStateChanged', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: () => {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n\n if (_libraryInstance) {\n _libraryInstance.off('bufferStateChanged', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDashJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-dash.js?");
9205
9216
 
9206
9217
  /***/ }),
9207
9218
 
@@ -9213,7 +9224,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9213
9224
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9214
9225
 
9215
9226
  "use strict";
9216
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nvar syncDaznDash = function syncDaznDash() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n realPosition = _calculateSyncDiffere.realPosition,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos, ping) {\n var seekRanges = _videoElement.buffered;\n var seekRange = {};\n\n for (var i = 0; i < seekRanges.length; i++) {\n var _c_start = seekRanges.start(i);\n\n var _c_end = seekRanges.end(i);\n\n if (!seekRange.start || _c_start < seekRange.start) {\n seekRange.start = _c_start;\n }\n\n if (!seekRange.end || _c_end > seekRange.end) {\n seekRange.end = _c_end;\n }\n }\n\n var position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position: position,\n realPostion: position,\n isBufferSufficient: true\n };\n } else if (position < seekRange.start) {\n room._log(\"Syncing to \".concat(seekRange.start, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.start + 0.5,\n realPostion: position,\n isBufferSufficient: false\n };\n } else if (position > seekRange.end) {\n room._log(\"Syncing to \".concat(seekRange.end, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.end - 0.5,\n realPostion: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPostion: position,\n isBufferSufficient: false\n };\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve, reject) {\n if (_videoElement.currentTime !== time) {\n var diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n }; // const seekTo = (time) => {\n // return new Promise((resolve, reject) => {\n // if(_videoElement.currentTime !== time) {\n // let __ = Date.now();\n // isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n // _videoElement.addEventListener('playing', () => {\n // room._log(`It took the player ${(Date.now() - __) / 1000} seconds to seek `);\n // isProgrammaticallySeeked = false;\n // resolve();\n // }, {once:true});\n // _videoElement.currentTime = time;\n // } else resolve()\n // });\n // };\n\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\n room._log(\"I've been asked for position even if we don't have player attached.\\n Does it mean I'm the master?\");\n\n return Promise.resolve();\n }\n\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function fn(msg) {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, _this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, _this);\n room.sendMessage(room.handleId, {\n body: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function clientPaused() {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n var propagateMasterFunc = function propagateMasterFunc() {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _libraryInstance = libraryInstance;\n _videoElement = _libraryInstance.videoElement;\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _libraryInstance.addEventListener('buffer', handleStalledWaiting);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n\n if (_libraryInstance) {\n _libraryInstance.removeEventListener('buffer', handleStalledWaiting);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDaznDash);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-dazn-dash.js?");
9227
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nconst syncDaznDash = function () {\n let {\n room,\n wt,\n roomSession,\n emitter\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n //SYNC VARS\n let _libraryInstance = null;\n let _videoElement = null;\n const syncDefaultWaitTime = 60000;\n const syncShortWaitTime = 10000;\n const maxSyncThreshold = 0.5;\n const maxSyncTries = 3;\n let currentSyncRetry = 0;\n let syncWaitId = null;\n let syncNextWaitTime = null;\n let stopFlag = false;\n let isSyncing = false;\n let playbackRate = 2;\n let isPlaying = false;\n let isPreloading = true;\n let isProgrammaticallySeeked = false;\n let shouldPropagateMaster = false;\n\n const startSyncLoop = () => {\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n const loop = () => {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(() => {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n const stopSyncLoop = () => {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n const restartSyncLoop = () => {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n const setNextWaitTime = function () {\n let didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n const sync = () => {\n return getSyncData().then(syncData => {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n const syncStartTime = Date.now();\n const {\n position,\n realPosition,\n isBufferSufficient\n } = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping);\n const currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekTo(position).then(() => {\n const seekDuration = (Date.now() - syncStartTime) / 1000;\n const syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n const didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(e => {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(() => {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n const handleAddLocalParticipant = () => {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', () => {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n const handleAddRemoteParticipant = () => {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n const isConnected = () => {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n const parseDataEvents = function () {\n let 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(() => {});\n }\n };\n\n const getCurrentSegmentPosition = () => {\n let position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n const calculateSyncDifferenceTime = (fragmentSn, fragmentPos, ping) => {\n let seekRanges = _videoElement.buffered;\n let seekRange = {};\n\n for (let i = 0; i < seekRanges.length; i++) {\n let _c_start = seekRanges.start(i);\n\n let _c_end = seekRanges.end(i);\n\n if (!seekRange.start || _c_start < seekRange.start) {\n seekRange.start = _c_start;\n }\n\n if (!seekRange.end || _c_end > seekRange.end) {\n seekRange.end = _c_end;\n }\n }\n\n let position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position,\n realPostion: position,\n isBufferSufficient: true\n };\n } else if (position < seekRange.start) {\n room._log(\"Syncing to \".concat(seekRange.start, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.start + 0.5,\n realPostion: position,\n isBufferSufficient: false\n };\n } else if (position > seekRange.end) {\n room._log(\"Syncing to \".concat(seekRange.end, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.end - 0.5,\n realPostion: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPostion: position,\n isBufferSufficient: false\n };\n };\n\n const seekTo = time => {\n return new Promise((resolve, reject) => {\n if (_videoElement.currentTime !== time) {\n let diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n let wasPaused = false;\n\n let __ = () => {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(() => {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(() => {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n let __ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', () => {\n room._log(\"It took the player \".concat((Date.now() - __) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n }; // const seekTo = (time) => {\n // return new Promise((resolve, reject) => {\n // if(_videoElement.currentTime !== time) {\n // let __ = Date.now();\n // isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n // _videoElement.addEventListener('playing', () => {\n // room._log(`It took the player ${(Date.now() - __) / 1000} seconds to seek `);\n // isProgrammaticallySeeked = false;\n // resolve();\n // }, {once:true});\n // _videoElement.currentTime = time;\n // } else resolve()\n // });\n // };\n\n\n const handlePlaying = () => {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n const handlePause = () => {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPlaying = !_videoElement.paused;\n };\n\n const handleStalledWaiting = () => {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPreloading = _videoElement.paused;\n }\n };\n\n const 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 let fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n const getSyncData = () => {\n room._log('Sending roomSync request');\n\n let roomId = room.roomId;\n let fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise((resolve, reject) => {\n let now = new Date().getTime();\n let ping = null;\n let sid = setTimeout(() => {\n room.off('data', fn, this);\n reject('Timeout');\n }, 3000);\n let body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n let fn = msg => {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, this);\n room.sendMessage(room.handleId, {\n body\n }).then(fn).catch(e => {\n room.off('data', fn, this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n const clientPaused = () => {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n const propagateMasterFunc = () => {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function () {\n let {\n libraryInstance,\n propagateMaster = false\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _libraryInstance = libraryInstance;\n _videoElement = _libraryInstance.videoElement;\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (shouldPropagateMaster) {\n propagateMasterFunc().catch(() => {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', () => {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _libraryInstance.addEventListener('buffer', handleStalledWaiting);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: () => {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n\n if (_libraryInstance) {\n _libraryInstance.removeEventListener('buffer', handleStalledWaiting);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDaznDash);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-dazn-dash.js?");
9217
9228
 
9218
9229
  /***/ }),
9219
9230
 
@@ -9225,7 +9236,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9225
9236
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9226
9237
 
9227
9238
  "use strict";
9228
- eval("__webpack_require__.r(__webpack_exports__);\nfunction _objectDestructuringEmpty(obj) { if (obj == null) throw new TypeError(\"Cannot destructure undefined\"); }\n\nvar syncDisabled = function syncDisabled() {\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 var handleAddLocalParticipant = function handleAddLocalParticipant() {\n removeMaster();\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n removeMaster();\n };\n\n var handleRemoveRemoteParticipant = function handleRemoveRemoteParticipant() {\n removeMaster();\n };\n\n var removeMaster = function removeMaster() {\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 return {\n __events: [],\n initialize: function initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n _objectDestructuringEmpty(_ref2);\n\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('removeRemoteParticipant', handleRemoveRemoteParticipant);\n },\n destroy: function destroy() {\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDisabled);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-disabled.js?");
9239
+ eval("__webpack_require__.r(__webpack_exports__);\nconst syncDisabled = function () {\n let {\n room,\n wt,\n roomSession,\n emitter\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n const handleAddLocalParticipant = () => {\n removeMaster();\n };\n\n const handleAddRemoteParticipant = () => {\n removeMaster();\n };\n\n const handleRemoveRemoteParticipant = () => {\n removeMaster();\n };\n\n const removeMaster = () => {\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 return {\n __events: [],\n initialize: function () {\n let {} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('removeRemoteParticipant', handleRemoveRemoteParticipant);\n },\n destroy: () => {\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDisabled);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-disabled.js?");
9229
9240
 
9230
9241
  /***/ }),
9231
9242
 
@@ -9237,7 +9248,7 @@ eval("__webpack_require__.r(__webpack_exports__);\nfunction _objectDestructuring
9237
9248
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9238
9249
 
9239
9250
  "use strict";
9240
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nvar syncDoris = function syncDoris() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n\n var startSyncLoop = function startSyncLoop() {\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n act = _calculateSyncDiffere.act,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n if (position && Math.abs(position) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekDoris(position, act).then(function () {\n var seekDuration = Date.now() - syncStartTime;\n\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos + seekDuration, syncData.ping),\n position = _calculateSyncDiffere2.position;\n\n var syncPrecision = Math.abs(position);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position;\n return (position = _libraryInstance.getCurrentDate()) === null || position === void 0 ? 0 : position.getTime();\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos) {\n var ping = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;\n\n var _pos;\n\n var currentTime = (_pos = _libraryInstance.getCurrentDate()) === null || _pos === void 0 ? null : _pos.getTime();\n\n if (currentTime && fragmentPos) {\n return {\n position: (fragmentPos + ping / 2 - currentTime) / 1000,\n act: fragmentPos + ping / 2,\n isBufferSufficient: true\n };\n } else {\n return {\n position: null,\n isBufferSufficient: false\n };\n }\n };\n\n var seekDoris = function seekDoris(time, act) {\n //https://mcorp.no/lib/mediasync.js\n return new Promise(function (resolve, reject) {\n if (time !== 0) {\n if (isSafari) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _libraryInstance.seekTo(new Date(act));\n } else {\n if (time > 0 && time < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n var diff = time; // _videoElement.addEventListener('waiting', __, {once:true});\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime += time;\n }\n }\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var sgtid = null;\n\n var stalledGenerator = function stalledGenerator() {\n clearTimeout(sgtid);\n sgtid = setTimeout(function () {\n if (_videoElement.paused === false) {\n handleStalledWaiting();\n }\n }, 1000);\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\n room._log(\"I've been asked for position even if we don't have player attached.\\n Does it mean I'm the master?\");\n\n return Promise.resolve();\n }\n\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function fn(msg) {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, _this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, _this);\n room.sendMessage(room.handleId, {\n body: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function clientPaused() {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n var propagateMasterFunc = function propagateMasterFunc() {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n dorisInstance = _ref2.dorisInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _libraryInstance = dorisInstance || libraryInstance;\n _videoElement = _libraryInstance.sourceHandler.getElement();\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _videoElement.addEventListener('timeupdate', stalledGenerator);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n\n if (_videoElement) {\n _videoElement.removeEventListener('timeupdate', stalledGenerator);\n\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDoris);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-doris.js?");
9251
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nconst syncDoris = function () {\n let {\n room,\n wt,\n roomSession,\n emitter\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n //SYNC VARS\n let _libraryInstance = null;\n let _videoElement = null;\n const syncDefaultWaitTime = 60000;\n const syncShortWaitTime = 10000;\n const maxSyncThreshold = 0.5;\n const maxSyncTries = 3;\n let currentSyncRetry = 0;\n let syncWaitId = null;\n let syncNextWaitTime = null;\n let stopFlag = false;\n let isSyncing = false;\n let playbackRate = 2;\n let isPlaying = false;\n let isPreloading = true;\n let isProgrammaticallySeeked = false;\n let shouldPropagateMaster = false;\n let isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n\n const startSyncLoop = () => {\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n const loop = () => {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(() => {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n const stopSyncLoop = () => {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n const restartSyncLoop = () => {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n const setNextWaitTime = function () {\n let didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n const sync = () => {\n return getSyncData().then(syncData => {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n const syncStartTime = Date.now();\n const {\n position,\n act,\n isBufferSufficient\n } = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping);\n\n if (position && Math.abs(position) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekDoris(position, act).then(() => {\n const seekDuration = Date.now() - syncStartTime;\n const {\n position\n } = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos + seekDuration, syncData.ping);\n const syncPrecision = Math.abs(position);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n const didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(e => {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(() => {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n const handleAddLocalParticipant = () => {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', () => {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n const handleAddRemoteParticipant = () => {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n const isConnected = () => {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n const parseDataEvents = function () {\n let 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(() => {});\n }\n };\n\n const getCurrentSegmentPosition = () => {\n var position;\n return (position = _libraryInstance.getCurrentDate()) === null || position === void 0 ? 0 : position.getTime();\n };\n\n const calculateSyncDifferenceTime = function (fragmentSn, fragmentPos) {\n let ping = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;\n\n var _pos;\n\n let currentTime = (_pos = _libraryInstance.getCurrentDate()) === null || _pos === void 0 ? null : _pos.getTime();\n\n if (currentTime && fragmentPos) {\n return {\n position: (fragmentPos + ping / 2 - currentTime) / 1000,\n act: fragmentPos + ping / 2,\n isBufferSufficient: true\n };\n } else {\n return {\n position: null,\n isBufferSufficient: false\n };\n }\n };\n\n const seekDoris = (time, act) => {\n //https://mcorp.no/lib/mediasync.js\n return new Promise((resolve, reject) => {\n if (time !== 0) {\n if (isSafari) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', () => {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _libraryInstance.seekTo(new Date(act));\n } else {\n if (time > 0 && time < 4) {\n room._log(\"Fast forward to seek...\");\n\n let wasPaused = false;\n\n let __ = () => {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n let diff = time; // _videoElement.addEventListener('waiting', __, {once:true});\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(() => {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(() => {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n let __ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', () => {\n room._log(\"It took the player \".concat((Date.now() - __) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime += time;\n }\n }\n } else resolve();\n });\n };\n\n const handlePlaying = () => {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n const handlePause = () => {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPlaying = !_videoElement.paused;\n };\n\n const handleStalledWaiting = () => {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPreloading = _videoElement.paused;\n }\n };\n\n let sgtid = null;\n\n const stalledGenerator = () => {\n clearTimeout(sgtid);\n sgtid = setTimeout(() => {\n if (_videoElement.paused === false) {\n handleStalledWaiting();\n }\n }, 1000);\n };\n\n const 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 let fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n const getSyncData = () => {\n room._log('Sending roomSync request');\n\n let roomId = room.roomId;\n let fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise((resolve, reject) => {\n let now = new Date().getTime();\n let ping = null;\n let sid = setTimeout(() => {\n room.off('data', fn, this);\n reject('Timeout');\n }, 3000);\n let body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n let fn = msg => {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, this);\n room.sendMessage(room.handleId, {\n body\n }).then(fn).catch(e => {\n room.off('data', fn, this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n const clientPaused = () => {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n const propagateMasterFunc = () => {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function () {\n let {\n dorisInstance,\n libraryInstance,\n propagateMaster = false\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _libraryInstance = dorisInstance || libraryInstance;\n _videoElement = _libraryInstance.sourceHandler.getElement();\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (shouldPropagateMaster) {\n propagateMasterFunc().catch(() => {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', () => {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _videoElement.addEventListener('timeupdate', stalledGenerator);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: () => {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n\n if (_videoElement) {\n _videoElement.removeEventListener('timeupdate', stalledGenerator);\n\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDoris);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-doris.js?");
9241
9252
 
9242
9253
  /***/ }),
9243
9254
 
@@ -9249,7 +9260,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9249
9260
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9250
9261
 
9251
9262
  "use strict";
9252
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n\n\nvar syncVodHlsJs = function syncVodHlsJs() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var _roomId = null;\n var _syncDisabled = false;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var seekingDebounceId = null;\n var seekingDebounceTimeout = 300;\n var isPlaying = false;\n var isProgrammaticallySeeked = false;\n var isForcedMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (_syncDisabled) {\n room._log('--- Sync loop will not start due to sync force disabled ---');\n\n return;\n }\n\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (syncData.masterFragmentSn) {\n playMedia();\n } else {\n pauseMedia();\n }\n\n if (position && Math.abs(position - currentPosition) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(position + (isPlaying ? seekDuration : 0) - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement) {\n //TODO: shit fix ... data channel with other participant is not opened yet so we wait\n setTimeout(function () {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }, 1000);\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var handleRemoveRemoteParticipant = function handleRemoveRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var buffering = function buffering(event) {\n var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n if (data.details === 'bufferStalledError') {\n handleStalledWaiting();\n }\n };\n\n var executePlayerIotEvents = function executePlayerIotEvents(data) {\n var rid = _roomId || room.roomId;\n\n if (data.attributeName === 'playerReplay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n seekTo(0).then(function () {\n return playMedia();\n });\n }\n\n if (data.attributeName === 'playerPlay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n playMedia();\n }\n\n if (data.attributeName === 'playerPause' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n pauseMedia();\n }\n };\n\n var parseIotEvents = function parseIotEvents(data) {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(function (event) {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents(_objectSpread(_objectSpread({}, event), {}, {\n roomId: data.roomId,\n userId: data.userId\n }));\n }\n });\n }\n\n if (data.operation === 'sendMessage') {\n executePlayerIotEvents(data);\n }\n }\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n } else if (msg.videoroom === 'message') {\n // ignoring non studio commands if master\n if (isForcedMaster && msg.from !== null) {\n return;\n }\n\n if (_syncDisabled) {\n return;\n }\n\n if (msg.user_action === 'sync_seeking') {\n seekMedia(msg).catch(function () {});\n } else if (msg.user_action === 'sync_seeked') {} else if (msg.user_action === 'sync_play' || msg.action === 'sync_play') {\n playMedia();\n } else if (msg.user_action === 'sync_pause' || msg.action === 'sync_pause') {\n pauseMedia();\n }\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn) {\n var fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n var seekMedia = function seekMedia(msg) {\n msg = _objectSpread({\n userId: msg.from\n }, msg.text && JSON.parse(msg.text));\n\n if (msg.handleId !== room.handleId) {\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0),\n position = _calculateSyncDiffere2.position,\n isBufferSufficient = _calculateSyncDiffere2.isBufferSufficient; //TODO: right ping\n\n\n if (position) {\n return seekTo(position).then(function () {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n var prePlay = function prePlay() {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n var wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(function () {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(function () {\n return true;\n }).finally(function () {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n var playMedia = function playMedia() {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(function () {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n var pauseMedia = function pauseMedia() {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', function () {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve) {\n if (_videoElement.currentTime !== time) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('seeked', function () {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(function () {});\n }\n };\n\n var handleSeeking = function handleSeeking() {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(function () {\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n roomSession.sendSystemMessage('sync_seeking', {\n timestamp: new Date().getTime(),\n handleId: room.handleId,\n fragment: \"0\",\n //isPlaying ? \"1\":\"0\",\n fragment_pos: Number(fragmentPosition)\n }, undefined, null).catch(function () {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n var handleSeeked = function handleSeeked() {};\n\n var handleEnded = function handleEnded() {};\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_videoElement) {\n room._log(\"I've been asked for position even if we don't have player attached.\\n Does it mean I'm the master?\");\n\n return Promise.resolve();\n }\n\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function fn(msg) {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, _this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, _this);\n room.sendMessage(room.handleId, {\n body: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function clientPaused() {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n var propagateMasterFunc = function propagateMasterFunc() {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n hlsInstance = _ref2.hlsInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster,\n _ref2$isStudio = _ref2.isStudio,\n isStudio = _ref2$isStudio === void 0 ? false : _ref2$isStudio,\n roomId = _ref2.roomId,\n syncDisabled = _ref2.syncDisabled;\n\n _libraryInstance = hlsInstance || libraryInstance; // backwards comp;\n\n _videoElement = _libraryInstance.media;\n _roomId = roomId;\n _syncDisabled = syncDisabled;\n\n if (!_libraryInstance) {\n room._log('No hls.js player instance!');\n\n return;\n }\n\n emitter.emit('playerSyncing', false);\n isForcedMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.on('data', parseDataEvents);\n wt.iot.$on('message', parseIotEvents);\n\n if (isForcedMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_libraryInstance && _videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(function () {\n _libraryInstance.on('hlsError', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n\n _videoElement.addEventListener('seeking', handleSeeking);\n\n _videoElement.addEventListener('seeked', handleSeeked);\n\n _videoElement.addEventListener('ended', handleEnded);\n\n startSyncLoop();\n });\n }\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_libraryInstance) {\n _libraryInstance.off('hlsError', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _libraryInstance = null;\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodHlsJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-hls-vod.js?");
9263
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nconst syncVodHlsJs = function () {\n let {\n room,\n wt,\n roomSession,\n emitter\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n //SYNC VARS\n let _libraryInstance = null;\n let _videoElement = null;\n let _roomId = null;\n let _syncDisabled = false;\n const syncDefaultWaitTime = 60000;\n const syncShortWaitTime = 10000;\n const maxSyncThreshold = 0.5;\n const maxSyncTries = 3;\n let currentSyncRetry = 0;\n let syncWaitId = null;\n let syncNextWaitTime = null;\n let stopFlag = false;\n let isSyncing = false;\n let seekingDebounceId = null;\n let seekingDebounceTimeout = 300;\n let isPlaying = false;\n let isProgrammaticallySeeked = false;\n let isForcedMaster = false;\n\n const 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 const loop = () => {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(() => {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n const stopSyncLoop = () => {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n const restartSyncLoop = () => {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n const setNextWaitTime = function () {\n let didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n const sync = () => {\n return getSyncData().then(syncData => {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n const syncStartTime = Date.now();\n const {\n position,\n isBufferSufficient\n } = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping);\n const 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(() => {\n const seekDuration = (Date.now() - syncStartTime) / 1000;\n const 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 const didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(e => {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(() => {\n setNextWaitTime(true);\n });\n };\n\n const 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(() => {\n _videoElement.addEventListener('progress', () => {\n restartSyncLoop();\n }, {\n once: true\n });\n }, 1000);\n }\n };\n\n const handleAddRemoteParticipant = () => {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n const handleRemoveRemoteParticipant = () => {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n const isConnected = () => {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n const buffering = function (event) {\n let data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n if (data.details === 'bufferStalledError') {\n handleStalledWaiting();\n }\n };\n\n const executePlayerIotEvents = data => {\n let 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(() => playMedia());\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 const parseIotEvents = data => {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(event => {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents({ ...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 const parseDataEvents = function () {\n let 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(() => {});\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(() => {});\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 const getCurrentSegmentPosition = () => {\n let position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n const calculateSyncDifferenceTime = function (fragmentSn) {\n let fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n let ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n const seekMedia = msg => {\n msg = {\n userId: msg.from,\n ...(msg.text && JSON.parse(msg.text))\n };\n\n if (msg.handleId !== room.handleId) {\n const {\n position,\n isBufferSufficient\n } = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0); //TODO: right ping\n\n if (position) {\n return seekTo(position).then(() => {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n const prePlay = () => {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n let wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(() => {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(() => true).finally(() => {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n const playMedia = () => {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(() => {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n const pauseMedia = () => {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', () => {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n const seekTo = time => {\n return new Promise(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', () => {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n const handlePlaying = () => {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(() => {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n const handlePause = () => {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(() => {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n const handleStalledWaiting = () => {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(() => {});\n }\n };\n\n const handleSeeking = () => {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(() => {\n let 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(() => {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n const handleSeeked = () => {};\n\n const handleEnded = () => {};\n\n const 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 let fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n const getSyncData = () => {\n room._log('Sending roomSync request');\n\n let roomId = room.roomId;\n let fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise((resolve, reject) => {\n let now = new Date().getTime();\n let ping = null;\n let sid = setTimeout(() => {\n room.off('data', fn, this);\n reject('Timeout');\n }, 3000);\n let body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n let fn = msg => {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, this);\n room.sendMessage(room.handleId, {\n body\n }).then(fn).catch(e => {\n room.off('data', fn, this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n const clientPaused = () => {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n const propagateMasterFunc = () => {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function () {\n let {\n hlsInstance,\n libraryInstance,\n propagateMaster = false,\n isStudio = false,\n roomId,\n syncDisabled\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\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(() => {});\n }\n\n if (_libraryInstance && _videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(() => {\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: () => {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_libraryInstance) {\n _libraryInstance.off('hlsError', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _libraryInstance = null;\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodHlsJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-hls-vod.js?");
9253
9264
 
9254
9265
  /***/ }),
9255
9266
 
@@ -9261,7 +9272,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9261
9272
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9262
9273
 
9263
9274
  "use strict";
9264
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n/*\n * TODO:\n * Sync we get\n * machineTimestamp = now\n * ping = (endRequestTimestamp - startRequestTimestamp) / 2\n * clockDifference = (serverTimestamp - machineTimestamp - ping)\n *\n *\n * usable vars : (now +- clockDifference) === currentServerTimestamp ---> when event was received\n * : (otherMachineTimestamp +- otherMachineClockDifference) === currentServerTimestamp ---> when event was sent\n *\n *\n * ping: (this user currentServerTimestamp a.k.a when event was received) - (remote user currentServerTimestamp a.k.a. when event was sent )\n *\n *\n * */\n\n\nvar syncHlsJs = function syncHlsJs() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var currentFragmentSn = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n if (position && Math.abs(position) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekBy(position).then(function () {\n var seekDuration = Date.now() - syncStartTime;\n\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos + seekDuration, syncData.ping),\n position = _calculateSyncDiffere2.position,\n isBufferSufficient = _calculateSyncDiffere2.isBufferSufficient;\n\n var syncPrecision = Math.abs(position);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration / 1000));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var buffering = function buffering(event) {\n var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n if (data.details === 'bufferStalledError') {\n handleStalledWaiting();\n }\n };\n\n var hlsFragChanged = function hlsFragChanged(event, data) {\n currentFragmentSn = data.frag.sn;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var _currentFragment$body;\n\n var fragments = _libraryInstance.streamController.fragmentTracker.fragments;\n\n if (!fragments) {\n return 0;\n }\n\n var currentFragment = fragments[Object.keys(fragments).find(function (key) {\n return key.indexOf(currentFragmentSn) > -1;\n })];\n\n if (!currentFragment) {\n return 0;\n }\n\n return Math.max((_libraryInstance.streamController.lastCurrentTime - (((_currentFragment$body = currentFragment.body) === null || _currentFragment$body === void 0 ? void 0 : _currentFragment$body.startPTS) || 0)) * 1000, 0);\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(masterFragmentSn, masterFragmentPos, ping) {\n var _currentFragment$body2;\n\n var fragments = _libraryInstance.streamController.fragmentTracker.fragments;\n var fragmentNumbers = Object.keys(fragments).map(function (key) {\n return parseInt(key.slice(key.lastIndexOf('_') + 1));\n }).sort(function (a, b) {\n return a - b;\n }); // our position in fragment\n //let currentFragmentSn = currentFragmentSn;\n\n var currentFragment = fragments[Object.keys(fragments).find(function (key) {\n return key.indexOf(currentFragmentSn) > -1;\n })];\n\n if (!currentFragment) {\n room._log('Current fragment not found, what now?', currentFragmentSn);\n\n return {\n position: null,\n isBufferSufficient: false\n };\n }\n\n var currentFragmentPos = Math.max((_libraryInstance.streamController.lastCurrentTime - (((_currentFragment$body2 = currentFragment.body) === null || _currentFragment$body2 === void 0 ? void 0 : _currentFragment$body2.startPTS) || 0)) * 1000, 0);\n var currentFragmentLength = currentFragment.body.duration * 1000;\n\n room._log(\"Our current fragment is: \".concat(currentFragmentSn));\n\n room._log(\"Our current fragment position is: \".concat(currentFragmentPos));\n\n room._log(\"Our current fragment length is: \".concat(currentFragmentLength)); // real server fragment\n\n\n var realMasterFragmentSn = masterFragmentSn; // real server position in fragment\n\n var realMasterFragmentPos = Math.max(ping / 2 + masterFragmentPos, 0); // simple flag\n\n var isBufferSufficient = false;\n /* Searching for fragment and in-fragment position when taking all delays into account */\n\n var relevantFragmentNumbers = fragmentNumbers.indexOf(masterFragmentSn) > -1 ? fragmentNumbers.slice(fragmentNumbers.indexOf(masterFragmentSn)) : [];\n\n var _loop = function _loop(i, len) {\n var sn = relevantFragmentNumbers[i];\n var fragment = fragments[Object.keys(fragments).find(function (key) {\n return key.indexOf(sn) > -1;\n })];\n var fragmentDuration = fragment.body.duration * 1000;\n\n room._log(\"Correction diff: \".concat(realMasterFragmentPos - fragmentDuration));\n\n realMasterFragmentSn = sn;\n\n if (realMasterFragmentPos - fragmentDuration > 0) {\n room._log(\"Not enough at fragment \".concat(sn));\n\n realMasterFragmentPos -= fragmentDuration;\n } else {\n room._log(\"Enough at fragment \".concat(sn));\n\n isBufferSufficient = true;\n return \"break\";\n }\n };\n\n for (var i = 0, len = relevantFragmentNumbers.length; i < len; i++) {\n var _ret = _loop(i, len);\n\n if (_ret === \"break\") break;\n } // We're not ready yet\n\n\n if (!isBufferSufficient) {\n room._log(\"We don't have required fragment \".concat(realMasterFragmentSn, \" yet\"));\n\n return {\n position: null,\n isBufferSufficient: false\n };\n } // We are too ahead\n\n\n if (realMasterFragmentSn < currentFragmentSn) {\n room._log(\"We are ahead of master...\");\n\n room._log(\"Real master fragment: \".concat(realMasterFragmentSn));\n\n room._log(\"Our fragment: \".concat(currentFragmentSn));\n\n var seekTime = currentFragmentPos - realMasterFragmentPos;\n\n var _relevantFragmentNumbers = fragmentNumbers.slice(fragmentNumbers.indexOf(realMasterFragmentSn));\n\n var _loop2 = function _loop2(_i, _len) {\n var sn = _relevantFragmentNumbers[_i];\n var fragment = fragments[Object.keys(fragments).find(function (key) {\n return key.indexOf(sn) > -1;\n })];\n var fragmentDuration = fragment.body.duration * 1000;\n\n if (sn >= currentFragmentSn) {\n return \"break\";\n }\n\n seekTime += fragmentDuration;\n };\n\n for (var _i = 0, _len = _relevantFragmentNumbers.length; _i < _len; _i++) {\n var _ret2 = _loop2(_i, _len);\n\n if (_ret2 === \"break\") break;\n }\n\n room._log(\"Sync difference is: \".concat(seekTime));\n\n return {\n position: seekTime / 1000 * -1,\n isBufferSufficient: true\n };\n } // We are behind or spot on\n else {\n room._log(\"We're behind or spot on master...\");\n\n room._log(\"Real master fragment: \".concat(realMasterFragmentSn));\n\n room._log(\"Our fragment: \".concat(currentFragmentSn));\n\n var _seekTime = realMasterFragmentPos - currentFragmentPos;\n\n var _relevantFragmentNumbers2 = fragmentNumbers.slice(fragmentNumbers.indexOf(currentFragmentSn));\n\n var _loop3 = function _loop3(_i2, _len2) {\n var sn = _relevantFragmentNumbers2[_i2];\n var fragment = fragments[Object.keys(fragments).find(function (key) {\n return key.indexOf(sn) > -1;\n })];\n var fragmentDuration = fragment.body.duration * 1000;\n\n if (sn >= realMasterFragmentSn) {\n return \"break\";\n }\n\n _seekTime += fragmentDuration;\n };\n\n for (var _i2 = 0, _len2 = _relevantFragmentNumbers2.length; _i2 < _len2; _i2++) {\n var _ret3 = _loop3(_i2, _len2);\n\n if (_ret3 === \"break\") break;\n }\n\n room._log(\"We can proceed with seek time: \".concat(_seekTime));\n\n return {\n position: _seekTime / 1000,\n isBufferSufficient: true\n };\n }\n };\n\n var seekBy = function seekBy(time) {\n //https://mcorp.no/lib/mediasync.js\n return new Promise(function (resolve, reject) {\n if (time !== 0) {\n if (time > 0 && time < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n var diff = time; // _videoElement.addEventListener('waiting', __, {once:true});\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime += time;\n }\n } else resolve();\n });\n };\n\n var seekTo = function seekTo(time) {\n //https://webtiming.github.io/timingsrc/ use this\n //https://mcorp.no/lib/mediasync.js\n return new Promise(function (resolve, reject) {\n if (_videoElement.currentTime !== time) {\n var diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _2 = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _2) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\n room._log(\"I've been asked for position even if we don't have player attached.\\n Does it mean I'm the master?\");\n\n return Promise.resolve();\n }\n\n var fragment = currentFragmentSn;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Fragment: \".concat(fragment));\n\n room._log(\"Fragment position: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(fragment),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragment = currentFragmentSn;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(fragment),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function fn(msg) {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, _this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, _this);\n room.sendMessage(room.handleId, {\n body: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function clientPaused() {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n var propagateMasterFunc = function propagateMasterFunc() {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n hlsInstance = _ref2.hlsInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _libraryInstance = hlsInstance || libraryInstance; // backwards comp;\n\n _videoElement = _libraryInstance.media;\n\n if (!_libraryInstance) {\n room._log('No hls.js player instance!');\n\n return;\n }\n\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _libraryInstance.once('hlsFragChanged', function () {\n restartSyncLoop();\n });\n }\n\n _libraryInstance.on('hlsError', buffering);\n\n _libraryInstance.on('hlsFragChanged', hlsFragChanged);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n\n if (_libraryInstance) {\n _libraryInstance.off('hlsError', buffering);\n\n _libraryInstance.off('hlsFragChanged', hlsFragChanged);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncHlsJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-hls.js?");
9275
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n/*\n * TODO:\n * Sync we get\n * machineTimestamp = now\n * ping = (endRequestTimestamp - startRequestTimestamp) / 2\n * clockDifference = (serverTimestamp - machineTimestamp - ping)\n *\n *\n * usable vars : (now +- clockDifference) === currentServerTimestamp ---> when event was received\n * : (otherMachineTimestamp +- otherMachineClockDifference) === currentServerTimestamp ---> when event was sent\n *\n *\n * ping: (this user currentServerTimestamp a.k.a when event was received) - (remote user currentServerTimestamp a.k.a. when event was sent )\n *\n *\n * */\n\n\nconst syncHlsJs = function () {\n let {\n room,\n wt,\n roomSession,\n emitter\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n //SYNC VARS\n let _libraryInstance = null;\n let _videoElement = null;\n let currentFragmentSn = null;\n const syncDefaultWaitTime = 60000;\n const syncShortWaitTime = 10000;\n const maxSyncThreshold = 0.5;\n const maxSyncTries = 3;\n let currentSyncRetry = 0;\n let syncWaitId = null;\n let syncNextWaitTime = null;\n let stopFlag = false;\n let isSyncing = false;\n let playbackRate = 2;\n let isPlaying = false;\n let isPreloading = true;\n let isProgrammaticallySeeked = false;\n let shouldPropagateMaster = false;\n\n const startSyncLoop = () => {\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n const loop = () => {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(() => {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n const stopSyncLoop = () => {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n const restartSyncLoop = () => {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n const setNextWaitTime = function () {\n let didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n const sync = () => {\n return getSyncData().then(syncData => {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n const syncStartTime = Date.now();\n const {\n position,\n isBufferSufficient\n } = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping);\n\n if (position && Math.abs(position) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekBy(position).then(() => {\n const seekDuration = Date.now() - syncStartTime;\n const {\n position,\n isBufferSufficient\n } = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos + seekDuration, syncData.ping);\n const syncPrecision = Math.abs(position);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration / 1000));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n const didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(e => {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(() => {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n const handleAddLocalParticipant = () => {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', () => {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n const handleAddRemoteParticipant = () => {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n const isConnected = () => {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n const buffering = function (event) {\n let data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n if (data.details === 'bufferStalledError') {\n handleStalledWaiting();\n }\n };\n\n const hlsFragChanged = (event, data) => {\n currentFragmentSn = data.frag.sn;\n };\n\n const parseDataEvents = function () {\n let 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(() => {});\n }\n };\n\n const getCurrentSegmentPosition = () => {\n var _currentFragment$body;\n\n let fragments = _libraryInstance.streamController.fragmentTracker.fragments;\n\n if (!fragments) {\n return 0;\n }\n\n let currentFragment = fragments[Object.keys(fragments).find(key => key.indexOf(currentFragmentSn) > -1)];\n\n if (!currentFragment) {\n return 0;\n }\n\n return Math.max((_libraryInstance.streamController.lastCurrentTime - (((_currentFragment$body = currentFragment.body) === null || _currentFragment$body === void 0 ? void 0 : _currentFragment$body.startPTS) || 0)) * 1000, 0);\n };\n\n const calculateSyncDifferenceTime = (masterFragmentSn, masterFragmentPos, ping) => {\n var _currentFragment$body2;\n\n let fragments = _libraryInstance.streamController.fragmentTracker.fragments;\n let fragmentNumbers = Object.keys(fragments).map(key => parseInt(key.slice(key.lastIndexOf('_') + 1))).sort(function (a, b) {\n return a - b;\n }); // our position in fragment\n //let currentFragmentSn = currentFragmentSn;\n\n let currentFragment = fragments[Object.keys(fragments).find(key => key.indexOf(currentFragmentSn) > -1)];\n\n if (!currentFragment) {\n room._log('Current fragment not found, what now?', currentFragmentSn);\n\n return {\n position: null,\n isBufferSufficient: false\n };\n }\n\n let currentFragmentPos = Math.max((_libraryInstance.streamController.lastCurrentTime - (((_currentFragment$body2 = currentFragment.body) === null || _currentFragment$body2 === void 0 ? void 0 : _currentFragment$body2.startPTS) || 0)) * 1000, 0);\n let currentFragmentLength = currentFragment.body.duration * 1000;\n\n room._log(\"Our current fragment is: \".concat(currentFragmentSn));\n\n room._log(\"Our current fragment position is: \".concat(currentFragmentPos));\n\n room._log(\"Our current fragment length is: \".concat(currentFragmentLength)); // real server fragment\n\n\n let realMasterFragmentSn = masterFragmentSn; // real server position in fragment\n\n let realMasterFragmentPos = Math.max(ping / 2 + masterFragmentPos, 0); // simple flag\n\n let isBufferSufficient = false;\n /* Searching for fragment and in-fragment position when taking all delays into account */\n\n let relevantFragmentNumbers = fragmentNumbers.indexOf(masterFragmentSn) > -1 ? fragmentNumbers.slice(fragmentNumbers.indexOf(masterFragmentSn)) : [];\n\n for (let i = 0, len = relevantFragmentNumbers.length; i < len; i++) {\n let sn = relevantFragmentNumbers[i];\n let fragment = fragments[Object.keys(fragments).find(key => key.indexOf(sn) > -1)];\n let fragmentDuration = fragment.body.duration * 1000;\n\n room._log(\"Correction diff: \".concat(realMasterFragmentPos - fragmentDuration));\n\n realMasterFragmentSn = sn;\n\n if (realMasterFragmentPos - fragmentDuration > 0) {\n room._log(\"Not enough at fragment \".concat(sn));\n\n realMasterFragmentPos -= fragmentDuration;\n } else {\n room._log(\"Enough at fragment \".concat(sn));\n\n isBufferSufficient = true;\n break;\n }\n } // We're not ready yet\n\n\n if (!isBufferSufficient) {\n room._log(\"We don't have required fragment \".concat(realMasterFragmentSn, \" yet\"));\n\n return {\n position: null,\n isBufferSufficient: false\n };\n } // We are too ahead\n\n\n if (realMasterFragmentSn < currentFragmentSn) {\n room._log(\"We are ahead of master...\");\n\n room._log(\"Real master fragment: \".concat(realMasterFragmentSn));\n\n room._log(\"Our fragment: \".concat(currentFragmentSn));\n\n let seekTime = currentFragmentPos - realMasterFragmentPos;\n let relevantFragmentNumbers = fragmentNumbers.slice(fragmentNumbers.indexOf(realMasterFragmentSn));\n\n for (let i = 0, len = relevantFragmentNumbers.length; i < len; i++) {\n let sn = relevantFragmentNumbers[i];\n let fragment = fragments[Object.keys(fragments).find(key => key.indexOf(sn) > -1)];\n let fragmentDuration = fragment.body.duration * 1000;\n\n if (sn >= currentFragmentSn) {\n break;\n }\n\n seekTime += fragmentDuration;\n }\n\n room._log(\"Sync difference is: \".concat(seekTime));\n\n return {\n position: seekTime / 1000 * -1,\n isBufferSufficient: true\n };\n } // We are behind or spot on\n else {\n room._log(\"We're behind or spot on master...\");\n\n room._log(\"Real master fragment: \".concat(realMasterFragmentSn));\n\n room._log(\"Our fragment: \".concat(currentFragmentSn));\n\n let seekTime = realMasterFragmentPos - currentFragmentPos;\n let relevantFragmentNumbers = fragmentNumbers.slice(fragmentNumbers.indexOf(currentFragmentSn));\n\n for (let i = 0, len = relevantFragmentNumbers.length; i < len; i++) {\n let sn = relevantFragmentNumbers[i];\n let fragment = fragments[Object.keys(fragments).find(key => key.indexOf(sn) > -1)];\n let fragmentDuration = fragment.body.duration * 1000;\n\n if (sn >= realMasterFragmentSn) {\n break;\n }\n\n seekTime += fragmentDuration;\n }\n\n room._log(\"We can proceed with seek time: \".concat(seekTime));\n\n return {\n position: seekTime / 1000,\n isBufferSufficient: true\n };\n }\n };\n\n const seekBy = time => {\n //https://mcorp.no/lib/mediasync.js\n return new Promise((resolve, reject) => {\n if (time !== 0) {\n if (time > 0 && time < 4) {\n room._log(\"Fast forward to seek...\");\n\n let wasPaused = false;\n\n let __ = () => {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n let diff = time; // _videoElement.addEventListener('waiting', __, {once:true});\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(() => {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(() => {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n let __ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', () => {\n room._log(\"It took the player \".concat((Date.now() - __) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime += time;\n }\n } else resolve();\n });\n };\n\n const seekTo = time => {\n //https://webtiming.github.io/timingsrc/ use this\n //https://mcorp.no/lib/mediasync.js\n return new Promise((resolve, reject) => {\n if (_videoElement.currentTime !== time) {\n let diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n let wasPaused = false;\n\n let __ = () => {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(() => {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(() => {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n let __ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', () => {\n room._log(\"It took the player \".concat((Date.now() - __) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n };\n\n const handlePlaying = () => {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n const handlePause = () => {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPlaying = !_videoElement.paused;\n };\n\n const handleStalledWaiting = () => {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPreloading = _videoElement.paused;\n }\n };\n\n const 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 let fragment = currentFragmentSn;\n let fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Fragment: \".concat(fragment));\n\n room._log(\"Fragment position: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(fragment),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n const getSyncData = () => {\n room._log('Sending roomSync request');\n\n let roomId = room.roomId;\n let fragment = currentFragmentSn;\n let fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise((resolve, reject) => {\n let now = new Date().getTime();\n let ping = null;\n let sid = setTimeout(() => {\n room.off('data', fn, this);\n reject('Timeout');\n }, 3000);\n let body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(fragment),\n fragment_pos: Number(fragmentPosition)\n };\n\n let fn = msg => {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, this);\n room.sendMessage(room.handleId, {\n body\n }).then(fn).catch(e => {\n room.off('data', fn, this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n const clientPaused = () => {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n const propagateMasterFunc = () => {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function () {\n let {\n hlsInstance,\n libraryInstance,\n propagateMaster = false\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _libraryInstance = hlsInstance || libraryInstance; // backwards comp;\n\n _videoElement = _libraryInstance.media;\n\n if (!_libraryInstance) {\n room._log('No hls.js player instance!');\n\n return;\n }\n\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (shouldPropagateMaster) {\n propagateMasterFunc().catch(() => {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _libraryInstance.once('hlsFragChanged', () => {\n restartSyncLoop();\n });\n }\n\n _libraryInstance.on('hlsError', buffering);\n\n _libraryInstance.on('hlsFragChanged', hlsFragChanged);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: () => {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n\n if (_libraryInstance) {\n _libraryInstance.off('hlsError', buffering);\n\n _libraryInstance.off('hlsFragChanged', hlsFragChanged);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncHlsJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-hls.js?");
9265
9276
 
9266
9277
  /***/ }),
9267
9278
 
@@ -9273,7 +9284,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9273
9284
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9274
9285
 
9275
9286
  "use strict";
9276
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n\n\nvar syncVodHlsJs = function syncVodHlsJs() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _videoElement = null;\n var _roomId = null;\n var _syncDisabled = false;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var seekingDebounceId = null;\n var seekingDebounceTimeout = 300;\n var isPlaying = false;\n var isProgrammaticallySeeked = false;\n var isForcedMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (_syncDisabled) {\n room._log('--- Sync loop will not start due to sync force disabled ---');\n\n return;\n }\n\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (syncData.masterFragmentSn) {\n playMedia();\n } else {\n pauseMedia();\n }\n\n if (position && Math.abs(position - currentPosition) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(position + (isPlaying ? seekDuration : 0) - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement) {\n //TODO: shit fix ... data channel with other participant is not opened yet so we wait\n setTimeout(function () {\n restartSyncLoop();\n }, 1000);\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var handleRemoveRemoteParticipant = function handleRemoveRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var executePlayerIotEvents = function executePlayerIotEvents(data) {\n var rid = _roomId || room.roomId;\n\n if (data.attributeName === 'playerReplay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n seekTo(0).then(function () {\n return playMedia();\n });\n }\n\n if (data.attributeName === 'playerPlay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n playMedia();\n }\n\n if (data.attributeName === 'playerPause' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n pauseMedia();\n }\n };\n\n var parseIotEvents = function parseIotEvents(data) {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(function (event) {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents(_objectSpread(_objectSpread({}, event), {}, {\n roomId: data.roomId,\n userId: data.userId\n }));\n }\n });\n }\n\n if (data.operation === 'sendMessage') {\n executePlayerIotEvents(data);\n }\n }\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n } else if (msg.videoroom === 'message') {\n // ignoring non studio commands if master\n if (isForcedMaster && msg.from !== null) {\n return;\n }\n\n if (_syncDisabled) {\n return;\n }\n\n if (msg.user_action === 'sync_seeking') {\n seekMedia(msg).catch(function () {});\n } else if (msg.user_action === 'sync_seeked') {} else if (msg.user_action === 'sync_play' || msg.action === 'sync_play') {\n playMedia();\n } else if (msg.user_action === 'sync_pause' || msg.action === 'sync_pause') {\n pauseMedia();\n }\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn) {\n var fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n var seekMedia = function seekMedia(msg) {\n msg = _objectSpread({\n userId: msg.from\n }, msg.text && JSON.parse(msg.text));\n\n if (msg.handleId !== room.handleId) {\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0),\n position = _calculateSyncDiffere2.position,\n isBufferSufficient = _calculateSyncDiffere2.isBufferSufficient; //TODO: right ping\n\n\n if (position) {\n return seekTo(position).then(function () {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n var prePlay = function prePlay() {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n var wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(function () {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(function () {\n return true;\n }).finally(function () {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n var playMedia = function playMedia() {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(function () {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n var pauseMedia = function pauseMedia() {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', function () {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve) {\n if (_videoElement.currentTime !== time) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('seeked', function () {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(function () {});\n }\n };\n\n var handleSeeking = function handleSeeking() {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(function () {\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n roomSession.sendSystemMessage('sync_seeking', {\n timestamp: new Date().getTime(),\n handleId: room.handleId,\n fragment: \"0\",\n //isPlaying ? \"1\":\"0\",\n fragment_pos: Number(fragmentPosition)\n }, undefined, null).catch(function () {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n var handleSeeked = function handleSeeked() {};\n\n var handleEnded = function handleEnded() {};\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_videoElement) {\n room._log(\"I've been asked for position even if we don't have player attached.\\n Does it mean I'm the master?\");\n\n return Promise.resolve();\n }\n\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function fn(msg) {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, _this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, _this);\n room.sendMessage(room.handleId, {\n body: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function clientPaused() {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n var propagateMasterFunc = function propagateMasterFunc() {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n videoElement = _ref2.videoElement,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster,\n _ref2$isStudio = _ref2.isStudio,\n isStudio = _ref2$isStudio === void 0 ? false : _ref2$isStudio,\n roomId = _ref2.roomId,\n syncDisabled = _ref2.syncDisabled;\n\n _videoElement = videoElement;\n _roomId = roomId;\n _syncDisabled = syncDisabled;\n\n if (!_videoElement) {\n room._log('No video element present!');\n\n return;\n }\n\n emitter.emit('playerSyncing', false);\n isForcedMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.on('data', parseDataEvents);\n wt.iot.$on('message', parseIotEvents);\n\n if (isForcedMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(function () {\n _videoElement.addEventListener('stalled', handleStalledWaiting);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n\n _videoElement.addEventListener('seeking', handleSeeking);\n\n _videoElement.addEventListener('seeked', handleSeeked);\n\n _videoElement.addEventListener('ended', handleEnded);\n\n startSyncLoop();\n });\n }\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_videoElement) {\n _videoElement.removeEventListener('stalled', handleStalledWaiting);\n\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodHlsJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-native-hls-vod.js?");
9287
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nconst syncVodHlsJs = function () {\n let {\n room,\n wt,\n roomSession,\n emitter\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n //SYNC VARS\n let _videoElement = null;\n let _roomId = null;\n let _syncDisabled = false;\n const syncDefaultWaitTime = 60000;\n const syncShortWaitTime = 10000;\n const maxSyncThreshold = 0.5;\n const maxSyncTries = 3;\n let currentSyncRetry = 0;\n let syncWaitId = null;\n let syncNextWaitTime = null;\n let stopFlag = false;\n let isSyncing = false;\n let seekingDebounceId = null;\n let seekingDebounceTimeout = 300;\n let isPlaying = false;\n let isProgrammaticallySeeked = false;\n let isForcedMaster = false;\n\n const 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 const loop = () => {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(() => {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n const stopSyncLoop = () => {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n const restartSyncLoop = () => {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n const setNextWaitTime = function () {\n let didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n const sync = () => {\n return getSyncData().then(syncData => {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n const syncStartTime = Date.now();\n const {\n position,\n isBufferSufficient\n } = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping);\n const 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(() => {\n const seekDuration = (Date.now() - syncStartTime) / 1000;\n const 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 const didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(e => {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(() => {\n setNextWaitTime(true);\n });\n };\n\n const 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(() => {\n restartSyncLoop();\n }, 1000);\n }\n };\n\n const handleAddRemoteParticipant = () => {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n const handleRemoveRemoteParticipant = () => {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n const isConnected = () => {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n const executePlayerIotEvents = data => {\n let 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(() => playMedia());\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 const parseIotEvents = data => {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(event => {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents({ ...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 const parseDataEvents = function () {\n let 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(() => {});\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(() => {});\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 const getCurrentSegmentPosition = () => {\n let position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n const calculateSyncDifferenceTime = function (fragmentSn) {\n let fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n let ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n const seekMedia = msg => {\n msg = {\n userId: msg.from,\n ...(msg.text && JSON.parse(msg.text))\n };\n\n if (msg.handleId !== room.handleId) {\n const {\n position,\n isBufferSufficient\n } = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0); //TODO: right ping\n\n if (position) {\n return seekTo(position).then(() => {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n const prePlay = () => {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n let wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(() => {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(() => true).finally(() => {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n const playMedia = () => {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(() => {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n const pauseMedia = () => {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', () => {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n const seekTo = time => {\n return new Promise(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', () => {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n const handlePlaying = () => {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(() => {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n const handlePause = () => {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(() => {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n const handleStalledWaiting = () => {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(() => {});\n }\n };\n\n const handleSeeking = () => {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(() => {\n let 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(() => {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n const handleSeeked = () => {};\n\n const handleEnded = () => {};\n\n const 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 let fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n const getSyncData = () => {\n room._log('Sending roomSync request');\n\n let roomId = room.roomId;\n let fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise((resolve, reject) => {\n let now = new Date().getTime();\n let ping = null;\n let sid = setTimeout(() => {\n room.off('data', fn, this);\n reject('Timeout');\n }, 3000);\n let body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n let fn = msg => {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, this);\n room.sendMessage(room.handleId, {\n body\n }).then(fn).catch(e => {\n room.off('data', fn, this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n const clientPaused = () => {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n const propagateMasterFunc = () => {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function () {\n let {\n videoElement,\n propagateMaster = false,\n isStudio = false,\n roomId,\n syncDisabled\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\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(() => {});\n }\n\n if (_videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(() => {\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: () => {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_videoElement) {\n _videoElement.removeEventListener('stalled', handleStalledWaiting);\n\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodHlsJs);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-native-hls-vod.js?");
9277
9288
 
9278
9289
  /***/ }),
9279
9290
 
@@ -9285,7 +9296,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9285
9296
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9286
9297
 
9287
9298
  "use strict";
9288
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nvar syncNativeHls = function syncNativeHls() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _videoElement = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n realPosition = _calculateSyncDiffere.realPosition,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos, ping) {\n var seekRanges = _videoElement.buffered;\n var seekRange = {};\n\n for (var i = 0; i < seekRanges.length; i++) {\n var _c_start = seekRanges.start(i);\n\n var _c_end = seekRanges.end(i);\n\n if (!seekRange.start || _c_start < seekRange.start) {\n seekRange.start = _c_start;\n }\n\n if (!seekRange.end || _c_end > seekRange.end) {\n seekRange.end = _c_end;\n }\n }\n\n var position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position: position,\n isBufferSufficient: true\n };\n } else if (position < seekRange.start) {\n room._log(\"Syncing to \".concat(seekRange.start, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.start + 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else if (position > seekRange.end) {\n room._log(\"Syncing to \".concat(seekRange.end, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.end - 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPosition: position,\n isBufferSufficient: false\n };\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve, reject) {\n if (_videoElement.currentTime !== time) {\n var diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var sgtid = null;\n\n var stalledGenerator = function stalledGenerator() {\n clearTimeout(sgtid);\n sgtid = setTimeout(function () {\n if (_videoElement.paused === false) {\n handleStalledWaiting();\n }\n }, 1000);\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_videoElement) {\n room._log(\"I've been asked for position even if we don't have player attached.\\n Does it mean I'm the master?\");\n\n return Promise.resolve();\n }\n\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function fn(msg) {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, _this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, _this);\n room.sendMessage(room.handleId, {\n body: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function clientPaused() {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n var propagateMasterFunc = function propagateMasterFunc() {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n videoElement = _ref2.videoElement,\n _ref2$syncOnLevelSwit = _ref2.syncOnLevelSwitch,\n syncOnLevelSwitch = _ref2$syncOnLevelSwit === void 0 ? false : _ref2$syncOnLevelSwit,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _videoElement = videoElement;\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _videoElement.addEventListener('timeupdate', stalledGenerator);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n\n if (_videoElement) {\n _videoElement.removeEventListener('timeupdate', stalledGenerator);\n\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncNativeHls);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-native-hls.js?");
9299
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nconst syncNativeHls = function () {\n let {\n room,\n wt,\n roomSession,\n emitter\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n //SYNC VARS\n let _videoElement = null;\n const syncDefaultWaitTime = 60000;\n const syncShortWaitTime = 10000;\n const maxSyncThreshold = 0.5;\n const maxSyncTries = 3;\n let currentSyncRetry = 0;\n let syncWaitId = null;\n let syncNextWaitTime = null;\n let stopFlag = false;\n let isSyncing = false;\n let playbackRate = 2;\n let isPlaying = false;\n let isPreloading = true;\n let isProgrammaticallySeeked = false;\n let shouldPropagateMaster = false;\n\n const startSyncLoop = () => {\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n const loop = () => {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(() => {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n const stopSyncLoop = () => {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n const restartSyncLoop = () => {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n const setNextWaitTime = function () {\n let didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n const sync = () => {\n return getSyncData().then(syncData => {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n const syncStartTime = Date.now();\n const {\n position,\n realPosition,\n isBufferSufficient\n } = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping);\n const currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekTo(position).then(() => {\n const seekDuration = (Date.now() - syncStartTime) / 1000;\n const syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n const didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(e => {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(() => {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n const handleAddLocalParticipant = () => {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', () => {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n const handleAddRemoteParticipant = () => {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n const isConnected = () => {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n const parseDataEvents = function () {\n let 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(() => {});\n }\n };\n\n const getCurrentSegmentPosition = () => {\n let position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n const calculateSyncDifferenceTime = (fragmentSn, fragmentPos, ping) => {\n let seekRanges = _videoElement.buffered;\n let seekRange = {};\n\n for (let i = 0; i < seekRanges.length; i++) {\n let _c_start = seekRanges.start(i);\n\n let _c_end = seekRanges.end(i);\n\n if (!seekRange.start || _c_start < seekRange.start) {\n seekRange.start = _c_start;\n }\n\n if (!seekRange.end || _c_end > seekRange.end) {\n seekRange.end = _c_end;\n }\n }\n\n let position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position,\n isBufferSufficient: true\n };\n } else if (position < seekRange.start) {\n room._log(\"Syncing to \".concat(seekRange.start, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.start + 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else if (position > seekRange.end) {\n room._log(\"Syncing to \".concat(seekRange.end, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.end - 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPosition: position,\n isBufferSufficient: false\n };\n };\n\n const seekTo = time => {\n return new Promise((resolve, reject) => {\n if (_videoElement.currentTime !== time) {\n let diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n let wasPaused = false;\n\n let __ = () => {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(() => {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(() => {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n let __ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', () => {\n room._log(\"It took the player \".concat((Date.now() - __) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n };\n\n const handlePlaying = () => {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n const handlePause = () => {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPlaying = !_videoElement.paused;\n };\n\n const handleStalledWaiting = () => {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPreloading = _videoElement.paused;\n }\n };\n\n let sgtid = null;\n\n const stalledGenerator = () => {\n clearTimeout(sgtid);\n sgtid = setTimeout(() => {\n if (_videoElement.paused === false) {\n handleStalledWaiting();\n }\n }, 1000);\n };\n\n const 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 let fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n const getSyncData = () => {\n room._log('Sending roomSync request');\n\n let roomId = room.roomId;\n let fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise((resolve, reject) => {\n let now = new Date().getTime();\n let ping = null;\n let sid = setTimeout(() => {\n room.off('data', fn, this);\n reject('Timeout');\n }, 3000);\n let body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n let fn = msg => {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, this);\n room.sendMessage(room.handleId, {\n body\n }).then(fn).catch(e => {\n room.off('data', fn, this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n const clientPaused = () => {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n const propagateMasterFunc = () => {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function () {\n let {\n videoElement,\n syncOnLevelSwitch = false,\n propagateMaster = false\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _videoElement = videoElement;\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (shouldPropagateMaster) {\n propagateMasterFunc().catch(() => {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', () => {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _videoElement.addEventListener('timeupdate', stalledGenerator);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: () => {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n\n if (_videoElement) {\n _videoElement.removeEventListener('timeupdate', stalledGenerator);\n\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncNativeHls);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-native-hls.js?");
9289
9300
 
9290
9301
  /***/ }),
9291
9302
 
@@ -9297,7 +9308,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9297
9308
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9298
9309
 
9299
9310
  "use strict";
9300
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n\n\nvar syncVodShakaDash = function syncVodShakaDash() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var _roomId = null;\n var _syncDisabled = false;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var seekingDebounceId = null;\n var seekingDebounceTimeout = 300;\n var isPlaying = false;\n var isProgrammaticallySeeked = false;\n var isForcedMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (_syncDisabled) {\n room._log('--- Sync loop will not start due to sync force disabled ---');\n\n return;\n }\n\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (syncData.masterFragmentSn) {\n playMedia();\n } else {\n pauseMedia();\n }\n\n if (position && Math.abs(position - currentPosition) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(position + (isPlaying ? seekDuration : 0) - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement) {\n //TODO: shit fix ... data channel with other participant is not opened yet so we wait\n setTimeout(function () {\n restartSyncLoop();\n }, 1000);\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var handleRemoveRemoteParticipant = function handleRemoveRemoteParticipant() {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var buffering = function buffering(event) {\n if (event.buffering) {\n handleStalledWaiting();\n }\n };\n\n var executePlayerIotEvents = function executePlayerIotEvents(data) {\n var rid = _roomId || room.roomId;\n\n if (data.attributeName === 'playerReplay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n seekTo(0).then(function () {\n return playMedia();\n });\n }\n\n if (data.attributeName === 'playerPlay' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n playMedia();\n }\n\n if (data.attributeName === 'playerPause' && (!rid || (data === null || data === void 0 ? void 0 : data.roomId) === rid)) {\n pauseMedia();\n }\n };\n\n var parseIotEvents = function parseIotEvents(data) {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(function (event) {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents(_objectSpread(_objectSpread({}, event), {}, {\n roomId: data.roomId,\n userId: data.userId\n }));\n }\n });\n }\n\n if (data.operation === 'sendMessage') {\n executePlayerIotEvents(data);\n }\n }\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n } else if (msg.videoroom === 'message') {\n // ignoring non studio commands if master\n if (isForcedMaster && msg.from !== null) {\n return;\n }\n\n if (_syncDisabled) {\n return;\n }\n\n if (msg.user_action === 'sync_seeking') {\n seekMedia(msg).catch(function () {});\n } else if (msg.user_action === 'sync_seeked') {} else if (msg.user_action === 'sync_play' || msg.action === 'sync_play') {\n playMedia();\n } else if (msg.user_action === 'sync_pause' || msg.action === 'sync_pause') {\n pauseMedia();\n }\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn) {\n var fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n var seekMedia = function seekMedia(msg) {\n msg = _objectSpread({\n userId: msg.from\n }, msg.text && JSON.parse(msg.text));\n\n if (msg.handleId !== room.handleId) {\n var _calculateSyncDiffere2 = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0),\n position = _calculateSyncDiffere2.position,\n isBufferSufficient = _calculateSyncDiffere2.isBufferSufficient; //TODO: right ping\n\n\n if (position) {\n return seekTo(position).then(function () {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n var prePlay = function prePlay() {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n var wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(function () {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(function () {\n return true;\n }).finally(function () {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n var playMedia = function playMedia() {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(function () {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n var pauseMedia = function pauseMedia() {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', function () {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve) {\n if (_videoElement.currentTime !== time) {\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('seeked', function () {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(function () {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(function () {});\n }\n };\n\n var handleSeeking = function handleSeeking() {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(function () {\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n roomSession.sendSystemMessage('sync_seeking', {\n timestamp: new Date().getTime(),\n handleId: room.handleId,\n fragment: \"0\",\n //isPlaying ? \"1\":\"0\",\n fragment_pos: Number(fragmentPosition)\n }, undefined, null).catch(function () {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n var handleSeeked = function handleSeeked() {};\n\n var handleEnded = function handleEnded() {};\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\n room._log(\"I've been asked for position even if we don't have player attached.\\n Does it mean I'm the master?\");\n\n return Promise.resolve();\n }\n\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function fn(msg) {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, _this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, _this);\n room.sendMessage(room.handleId, {\n body: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function clientPaused() {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n var propagateMasterFunc = function propagateMasterFunc() {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n shakaInstance = _ref2.shakaInstance,\n libraryInstance = _ref2.libraryInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster,\n _ref2$isStudio = _ref2.isStudio,\n isStudio = _ref2$isStudio === void 0 ? false : _ref2$isStudio,\n roomId = _ref2.roomId,\n syncDisabled = _ref2.syncDisabled;\n\n _libraryInstance = shakaInstance || libraryInstance;\n _videoElement = _libraryInstance.getMediaElement();\n _roomId = roomId;\n _syncDisabled = syncDisabled;\n\n if (!_libraryInstance) {\n console.log('No shaka player instance');\n return;\n }\n\n emitter.emit('playerSyncing', false);\n isForcedMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.on('data', parseDataEvents);\n wt.iot.$on('message', parseIotEvents);\n\n if (isForcedMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_libraryInstance && _videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(function () {\n _libraryInstance.addEventListener('buffering', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n\n _videoElement.addEventListener('seeking', handleSeeking);\n\n _videoElement.addEventListener('seeked', handleSeeked);\n\n _videoElement.addEventListener('ended', handleEnded);\n\n startSyncLoop();\n });\n }\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_libraryInstance) {\n _libraryInstance.removeEventListener('buffering', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _libraryInstance = null;\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodShakaDash);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-shaka-dash-vod.js?");
9311
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nconst syncVodShakaDash = function () {\n let {\n room,\n wt,\n roomSession,\n emitter\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n //SYNC VARS\n let _libraryInstance = null;\n let _videoElement = null;\n let _roomId = null;\n let _syncDisabled = false;\n const syncDefaultWaitTime = 60000;\n const syncShortWaitTime = 10000;\n const maxSyncThreshold = 0.5;\n const maxSyncTries = 3;\n let currentSyncRetry = 0;\n let syncWaitId = null;\n let syncNextWaitTime = null;\n let stopFlag = false;\n let isSyncing = false;\n let seekingDebounceId = null;\n let seekingDebounceTimeout = 300;\n let isPlaying = false;\n let isProgrammaticallySeeked = false;\n let isForcedMaster = false;\n\n const 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 const loop = () => {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(() => {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n const stopSyncLoop = () => {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n const restartSyncLoop = () => {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n const setNextWaitTime = function () {\n let didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n const sync = () => {\n return getSyncData().then(syncData => {\n if (syncData.isMaster || stopFlag) {\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (isForcedMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n const syncStartTime = Date.now();\n const {\n position,\n isBufferSufficient\n } = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping);\n const 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(() => {\n const seekDuration = (Date.now() - syncStartTime) / 1000;\n const 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 const didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(e => {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(() => {\n setNextWaitTime(true);\n });\n };\n\n const 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(() => {\n restartSyncLoop();\n }, 1000);\n }\n };\n\n const handleAddRemoteParticipant = () => {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n const handleRemoveRemoteParticipant = () => {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n };\n\n const isConnected = () => {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n const buffering = event => {\n if (event.buffering) {\n handleStalledWaiting();\n }\n };\n\n const executePlayerIotEvents = data => {\n let 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(() => playMedia());\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 const parseIotEvents = data => {\n if (data.event === 'template_updated') {\n if (data.operation === 'multi') {\n (data.value || []).forEach(event => {\n if (event.operation === 'sendMessage') {\n executePlayerIotEvents({ ...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 const parseDataEvents = function () {\n let 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(() => {});\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(() => {});\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 const getCurrentSegmentPosition = () => {\n let position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n const calculateSyncDifferenceTime = function (fragmentSn) {\n let fragmentPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n let ping = arguments.length > 2 ? arguments[2] : undefined;\n return {\n position: (fragmentPos + ping / 2) / 1000,\n isBufferSufficient: true\n };\n };\n\n const seekMedia = msg => {\n msg = {\n userId: msg.from,\n ...(msg.text && JSON.parse(msg.text))\n };\n\n if (msg.handleId !== room.handleId) {\n const {\n position,\n isBufferSufficient\n } = calculateSyncDifferenceTime(msg.fragment, msg.fragment_pos, 0); //TODO: right ping\n\n if (position) {\n return seekTo(position).then(() => {\n if (isForcedMaster) {\n propagateMasterFunc();\n }\n });\n } else {\n return Promise.resolve();\n }\n } else {\n return Promise.resolve();\n }\n };\n\n const prePlay = () => {\n if (_videoElement.currentTime > 0 || _videoElement.paused === false) {\n return Promise.resolve();\n }\n\n isProgrammaticallySeeked = true;\n let wasMuted = _videoElement.muted;\n _videoElement.muted = true;\n return _videoElement.play().then(() => {\n _videoElement.pause();\n\n _videoElement.currentTime = 0;\n return Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"wait\"])(100);\n }).catch(() => true).finally(() => {\n _videoElement.muted = wasMuted;\n isProgrammaticallySeeked = false;\n return true;\n });\n };\n\n const playMedia = () => {\n if (_videoElement && _videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.play().finally(() => {\n isProgrammaticallySeeked = false;\n });\n }\n };\n\n const pauseMedia = () => {\n if (_videoElement && !_videoElement.paused) {\n isProgrammaticallySeeked = true;\n\n _videoElement.addEventListener('pause', () => {\n isProgrammaticallySeeked = false;\n }, {\n once: true\n });\n\n _videoElement.pause();\n }\n };\n\n const seekTo = time => {\n return new Promise(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', () => {\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n } else resolve();\n });\n };\n\n const handlePlaying = () => {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_play', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(() => {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n const handlePause = () => {\n if (!isProgrammaticallySeeked) {\n roomSession.sendSystemMessage('sync_pause', {\n timestamp: new Date().getTime(),\n handleId: room.handleId\n }, undefined, null).catch(() => {});\n }\n\n isPlaying = !_videoElement.paused;\n };\n\n const handleStalledWaiting = () => {\n if (!isProgrammaticallySeeked) {\n clientPaused().catch(() => {});\n }\n };\n\n const handleSeeking = () => {\n clearTimeout(seekingDebounceId);\n\n if (!isProgrammaticallySeeked) {\n seekingDebounceId = setTimeout(() => {\n let 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(() => {});\n\n if (!isForcedMaster && !_syncDisabled) {\n pauseMedia();\n }\n }, seekingDebounceTimeout);\n }\n };\n\n const handleSeeked = () => {};\n\n const handleEnded = () => {};\n\n const 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 let fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n const getSyncData = () => {\n room._log('Sending roomSync request');\n\n let roomId = room.roomId;\n let fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise((resolve, reject) => {\n let now = new Date().getTime();\n let ping = null;\n let sid = setTimeout(() => {\n room.off('data', fn, this);\n reject('Timeout');\n }, 3000);\n let body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: isPlaying ? \"1\" : \"0\",\n fragment_pos: Number(fragmentPosition)\n };\n\n let fn = msg => {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, this);\n room.sendMessage(room.handleId, {\n body\n }).then(fn).catch(e => {\n room.off('data', fn, this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n const clientPaused = () => {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n const propagateMasterFunc = () => {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function () {\n let {\n shakaInstance,\n libraryInstance,\n propagateMaster = false,\n isStudio = false,\n roomId,\n syncDisabled\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\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(() => {});\n }\n\n if (_libraryInstance && _videoElement) {\n (propagateMaster || isStudio ? Promise.resolve() : prePlay()).then(() => {\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: () => {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('removeRemoteParticipant', handleRemoveRemoteParticipant);\n room.off('data', parseDataEvents);\n wt.iot.$off('message', parseIotEvents);\n\n if (_libraryInstance) {\n _libraryInstance.removeEventListener('buffering', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n\n _videoElement.removeEventListener('seeking', handleSeeking);\n\n _videoElement.removeEventListener('seeked', handleSeeked);\n\n _videoElement.removeEventListener('ended', handleEnded);\n }\n\n _libraryInstance = null;\n _videoElement = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncVodShakaDash);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-shaka-dash-vod.js?");
9301
9312
 
9302
9313
  /***/ }),
9303
9314
 
@@ -9309,7 +9320,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9309
9320
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9310
9321
 
9311
9322
  "use strict";
9312
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nvar syncDaznDash = function syncDaznDash() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _libraryInstance = null;\n var _videoElement = null;\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var buffering = function buffering(event) {\n if (event.buffering) {\n handleStalledWaiting();\n }\n };\n\n var startSyncLoop = function startSyncLoop() {\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n realPosition = _calculateSyncDiffere.realPosition,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos, ping) {\n var seekRanges = _videoElement.buffered;\n var seekRange = {};\n\n for (var i = 0; i < seekRanges.length; i++) {\n var _c_start = seekRanges.start(i);\n\n var _c_end = seekRanges.end(i);\n\n if (!seekRange.start || _c_start < seekRange.start) {\n seekRange.start = _c_start;\n }\n\n if (!seekRange.end || _c_end > seekRange.end) {\n seekRange.end = _c_end;\n }\n }\n\n var position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position: position,\n isBufferSufficient: true\n };\n } else if (position < seekRange.start) {\n room._log(\"Syncing to \".concat(seekRange.start, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.start + 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else if (position > seekRange.end) {\n room._log(\"Syncing to \".concat(seekRange.end, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.end - 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPosition: position,\n isBufferSufficient: false\n };\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve, reject) {\n if (_videoElement.currentTime !== time) {\n var diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var __ = function __() {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(function () {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var _ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', function () {\n room._log(\"It took the player \".concat((Date.now() - _) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n }; // const seekTo = (time) => {\n // return new Promise((resolve, reject) => {\n // if(_videoElement.currentTime !== time) {\n // let __ = Date.now();\n // isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n // _videoElement.addEventListener('playing', () => {\n // room._log(`It took the player ${(Date.now() - __) / 1000} seconds to seek `);\n // isProgrammaticallySeeked = false;\n // resolve();\n // }, {once:true});\n // _videoElement.currentTime = time;\n // } else resolve()\n // });\n // };\n\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_videoElement.paused;\n };\n\n var handleStalledWaiting = function handleStalledWaiting() {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _videoElement.paused;\n }\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_libraryInstance || !_videoElement) {\n room._log(\"I've been asked for position even if we don't have player attached.\\n Does it mean I'm the master?\");\n\n return Promise.resolve();\n }\n\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function fn(msg) {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, _this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, _this);\n room.sendMessage(room.handleId, {\n body: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function clientPaused() {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n var propagateMasterFunc = function propagateMasterFunc() {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n libraryInstance = _ref2.libraryInstance,\n shakaInstance = _ref2.shakaInstance,\n _ref2$propagateMaster = _ref2.propagateMaster,\n propagateMaster = _ref2$propagateMaster === void 0 ? false : _ref2$propagateMaster;\n\n _libraryInstance = libraryInstance || shakaInstance;\n _videoElement = _libraryInstance.getMediaElement();\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', function () {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _libraryInstance.addEventListener('buffering', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: function destroy() {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n\n if (_libraryInstance) {\n _libraryInstance.removeEventListener('buffering', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDaznDash);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-shaka-dash.js?");
9323
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n\n\nconst syncDaznDash = function () {\n let {\n room,\n wt,\n roomSession,\n emitter\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n //SYNC VARS\n let _libraryInstance = null;\n let _videoElement = null;\n const syncDefaultWaitTime = 60000;\n const syncShortWaitTime = 10000;\n const maxSyncThreshold = 0.5;\n const maxSyncTries = 3;\n let currentSyncRetry = 0;\n let syncWaitId = null;\n let syncNextWaitTime = null;\n let stopFlag = false;\n let isSyncing = false;\n let playbackRate = 2;\n let isPlaying = false;\n let isPreloading = true;\n let isProgrammaticallySeeked = false;\n let shouldPropagateMaster = false;\n\n const buffering = event => {\n if (event.buffering) {\n handleStalledWaiting();\n }\n };\n\n const startSyncLoop = () => {\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n const loop = () => {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(() => {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n const stopSyncLoop = () => {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n const restartSyncLoop = () => {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n const setNextWaitTime = function () {\n let didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n const sync = () => {\n return getSyncData().then(syncData => {\n if (syncData.isMaster) {\n if (_videoElement.paused) _videoElement.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n const syncStartTime = Date.now();\n const {\n position,\n realPosition,\n isBufferSufficient\n } = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping);\n const currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekTo(position).then(() => {\n const seekDuration = (Date.now() - syncStartTime) / 1000;\n const syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n const didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(e => {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(() => {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n const handleAddLocalParticipant = () => {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', () => {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n };\n\n const handleAddRemoteParticipant = () => {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n const isConnected = () => {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n const parseDataEvents = function () {\n let 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(() => {});\n }\n };\n\n const getCurrentSegmentPosition = () => {\n let position = _videoElement && _videoElement.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n const calculateSyncDifferenceTime = (fragmentSn, fragmentPos, ping) => {\n let seekRanges = _videoElement.buffered;\n let seekRange = {};\n\n for (let i = 0; i < seekRanges.length; i++) {\n let _c_start = seekRanges.start(i);\n\n let _c_end = seekRanges.end(i);\n\n if (!seekRange.start || _c_start < seekRange.start) {\n seekRange.start = _c_start;\n }\n\n if (!seekRange.end || _c_end > seekRange.end) {\n seekRange.end = _c_end;\n }\n }\n\n let position = (fragmentPos + ping / 2) / 1000;\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position,\n isBufferSufficient: true\n };\n } else if (position < seekRange.start) {\n room._log(\"Syncing to \".concat(seekRange.start, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.start + 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else if (position > seekRange.end) {\n room._log(\"Syncing to \".concat(seekRange.end, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.end - 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n realPosition: position,\n isBufferSufficient: false\n };\n };\n\n const seekTo = time => {\n return new Promise((resolve, reject) => {\n if (_videoElement.currentTime !== time) {\n let diff = time - _videoElement.currentTime;\n\n if (_videoElement.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n let wasPaused = false;\n\n let __ = () => {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false;\n reject('Stalled');\n }; // _videoElement.addEventListener('waiting', __, {once:true});\n\n\n _videoElement.addEventListener('stalled', __, {\n once: true\n });\n\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(() => {\n if (wasPaused) {\n _videoElement.pause();\n }\n\n _videoElement.playbackRate = 1;\n isProgrammaticallySeeked = false; // _videoElement.removeEventListener('waiting', __, {once:true});\n\n _videoElement.removeEventListener('stalled', __, {\n once: true\n });\n\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n isProgrammaticallySeeked = true;\n\n if (_videoElement.paused) {\n wasPaused = true;\n\n _videoElement.play().then(() => {\n _videoElement.playbackRate = playbackRate;\n });\n } else {\n _videoElement.playbackRate = playbackRate;\n }\n } else {\n room._log(\"Jump to seek...\");\n\n let __ = Date.now();\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _videoElement.addEventListener('playing', () => {\n room._log(\"It took the player \".concat((Date.now() - __) / 1000, \" seconds to seek \"));\n\n isProgrammaticallySeeked = false;\n resolve();\n }, {\n once: true\n });\n\n _videoElement.currentTime = time;\n }\n } else resolve();\n });\n }; // const seekTo = (time) => {\n // return new Promise((resolve, reject) => {\n // if(_videoElement.currentTime !== time) {\n // let __ = Date.now();\n // isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n // _videoElement.addEventListener('playing', () => {\n // room._log(`It took the player ${(Date.now() - __) / 1000} seconds to seek `);\n // isProgrammaticallySeeked = false;\n // resolve();\n // }, {once:true});\n // _videoElement.currentTime = time;\n // } else resolve()\n // });\n // };\n\n\n const handlePlaying = () => {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _videoElement.paused;\n isPlaying = !_videoElement.paused;\n };\n\n const handlePause = () => {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPlaying = !_videoElement.paused;\n };\n\n const handleStalledWaiting = () => {\n room._log('handleStalledWaiting');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPreloading = _videoElement.paused;\n }\n };\n\n const 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 let fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n const getSyncData = () => {\n room._log('Sending roomSync request');\n\n let roomId = room.roomId;\n let fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise((resolve, reject) => {\n let now = new Date().getTime();\n let ping = null;\n let sid = setTimeout(() => {\n room.off('data', fn, this);\n reject('Timeout');\n }, 3000);\n let body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n let fn = msg => {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, this);\n room.sendMessage(room.handleId, {\n body\n }).then(fn).catch(e => {\n room.off('data', fn, this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n const clientPaused = () => {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n const propagateMasterFunc = () => {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n initialize: function () {\n let {\n libraryInstance,\n shakaInstance,\n propagateMaster = false\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _libraryInstance = libraryInstance || shakaInstance;\n _videoElement = _libraryInstance.getMediaElement();\n shouldPropagateMaster = propagateMaster;\n isPlaying = _videoElement.paused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (shouldPropagateMaster) {\n propagateMasterFunc().catch(() => {});\n }\n\n if (_videoElement && _videoElement.paused === false) {\n _videoElement.addEventListener('progress', () => {\n restartSyncLoop();\n }, {\n once: true\n });\n }\n\n _libraryInstance.addEventListener('buffering', buffering);\n\n _videoElement.addEventListener('playing', handlePlaying);\n\n _videoElement.addEventListener('pause', handlePause);\n },\n destroy: () => {\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n\n if (_libraryInstance) {\n _libraryInstance.removeEventListener('buffering', buffering);\n }\n\n if (_videoElement) {\n _videoElement.removeEventListener('playing', handlePlaying);\n\n _videoElement.removeEventListener('pause', handlePause);\n }\n\n _libraryInstance = null;\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncDaznDash);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-shaka-dash.js?");
9313
9324
 
9314
9325
  /***/ }),
9315
9326
 
@@ -9321,7 +9332,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9321
9332
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9322
9333
 
9323
9334
  "use strict";
9324
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n/* harmony import */ var _wt_emitter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../wt-emitter */ \"./src/modules/wt-emitter.js\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n\n\n\nvar syncUniversal = function syncUniversal() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n room = _ref.room,\n wt = _ref.wt,\n roomSession = _ref.roomSession,\n emitter = _ref.emitter;\n\n //SYNC VARS\n var _emitter = Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])();\n\n var _playerInterface = null;\n var _playerInterfaceOptions = {\n isLive: true,\n ignoreBufferedTimeRanges: true,\n useSeekBy: false,\n syncBySegments: false,\n disableFastSeek: false\n };\n var syncDefaultWaitTime = 60000;\n var syncShortWaitTime = 10000;\n var maxSyncThreshold = 0.5;\n var maxSyncTries = 3;\n var waitForPlayingEventAfterSeek = 5000;\n var currentSyncRetry = 0;\n var syncWaitId = null;\n var syncNextWaitTime = null;\n var stopFlag = false;\n var isSyncing = false;\n var playbackRate = 2;\n var isPlaying = false;\n var isPreloading = true;\n var isProgrammaticallySeeked = false;\n var shouldPropagateMaster = false;\n\n var startSyncLoop = function startSyncLoop() {\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n var loop = function loop() {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(function () {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n var stopSyncLoop = function stopSyncLoop() {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n var restartSyncLoop = function restartSyncLoop() {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n var setNextWaitTime = function setNextWaitTime() {\n var didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n var sync = function sync() {\n return getSyncData().then(function (syncData) {\n if (syncData.isMaster) {\n if (_playerInterface.isPaused) _playerInterface.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n var syncStartTime = Date.now();\n\n var _calculateSyncDiffere = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping),\n position = _calculateSyncDiffere.position,\n realPosition = _calculateSyncDiffere.realPosition,\n isBufferSufficient = _calculateSyncDiffere.isBufferSufficient;\n\n var currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekTo(position).then(function () {\n var seekDuration = (Date.now() - syncStartTime) / 1000;\n var syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(realPosition, seekDuration, getCurrentSegmentPosition());\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration, \" seconds\"));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n var didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(function (e) {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(function () {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n var handleAddLocalParticipant = function handleAddLocalParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_playerInterface.isPaused === false) {\n _emitter.once('timeupdate', restartSyncLoop);\n }\n };\n\n var handleAddRemoteParticipant = function handleAddRemoteParticipant() {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n var isConnected = function isConnected() {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n var parseDataEvents = function parseDataEvents() {\n var msg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (msg.videoroom === 'sync_source_set' && msg.wt_channel_id != \"\") {\n emitter.emit('changePlayerSource', msg.wt_channel_id);\n } else if (msg.videoroom === 'sync_request') {\n roomSyncSend(msg.sync_slave_id).catch(function () {});\n }\n };\n\n var getCurrentSegmentPosition = function getCurrentSegmentPosition() {\n var position = _playerInterface.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n var calculateSyncDifferenceTime = function calculateSyncDifferenceTime(fragmentSn, fragmentPos, ping) {\n var seekRanges = _playerInterface.buffered;\n var position = (fragmentPos + ping / 2) / 1000;\n\n if (seekRanges && !_playerInterfaceOptions.ignoreBufferedTimeRanges) {\n var seekRange = {};\n\n for (var i = 0; i < seekRanges.length; i++) {\n var _c_start = seekRanges.start(i);\n\n var _c_end = seekRanges.end(i);\n\n if (!seekRange.start || _c_start < seekRange.start) {\n seekRange.start = _c_start;\n }\n\n if (!seekRange.end || _c_end > seekRange.end) {\n seekRange.end = _c_end;\n }\n }\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position: position,\n realPosition: position,\n isBufferSufficient: true\n };\n } else if (position < seekRange.start) {\n room._log(\"Syncing to \".concat(seekRange.start, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.start + 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else if (position > seekRange.end) {\n room._log(\"Syncing to \".concat(seekRange.end, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.end - 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n isBufferSufficient: false\n };\n } else {\n return {\n position: position,\n realPosition: position,\n isBufferSufficient: true\n };\n }\n };\n\n var seekTo = function seekTo(time) {\n return new Promise(function (resolve, reject) {\n if (_playerInterface.currentTime !== time) {\n var diff = time - _playerInterface.currentTime;\n\n if (_playerInterface.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n var wasPaused = false;\n\n var _handleFailed = function _handleFailed() {\n if (wasPaused) {\n _playerInterface.pause();\n }\n\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n var _fastForward = function _fastForward() {\n isProgrammaticallySeeked = true;\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(function () {\n _emitter.off('stalled', _handleFailed);\n\n if (wasPaused && !_playerInterfaceOptions.isLive) {\n _playerInterface.pause();\n }\n\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n\n _playerInterface.setPlaybackRate(playbackRate);\n };\n\n _emitter.once('stalled', _handleFailed);\n\n if (_playerInterface.isPaused) {\n wasPaused = true;\n\n _playerInterface.play().then(function () {\n _fastForward();\n }).catch(_handleFailed);\n } else {\n _fastForward();\n }\n } else {\n room._log(\"Jump to seek...\");\n\n var currentTimestamp = Date.now();\n var __failsafeId = null;\n\n var _resolve = function _resolve() {\n clearTimeout(__failsafeId);\n __failsafeId = null;\n isProgrammaticallySeeked = false;\n\n room._log(\"It took the player \".concat((Date.now() - currentTimestamp) / 1000, \" seconds to seek \"));\n\n resolve();\n };\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _emitter.once('playing', _resolve);\n\n __failsafeId = setTimeout(_resolve, waitForPlayingEventAfterSeek);\n\n _playerInterface.seek(time);\n }\n } else resolve();\n });\n };\n\n var handlePlaying = function handlePlaying() {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _playerInterface.isPaused;\n isPlaying = !_playerInterface.isPaused;\n };\n\n var handlePause = function handlePause() {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPlaying = !_playerInterface.isPaused;\n };\n\n var handleBuffering = function handleBuffering() {\n room._log('handleBuffering');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(function () {});\n isPreloading = _playerInterface.isPaused;\n }\n };\n\n var roomSyncSend = function roomSyncSend(slaveId) {\n if (!_playerInterface) {\n room._log(\"I've been asked for position even if we don't have player attached.\\n Does it mean I'm the master?\");\n\n return Promise.resolve();\n }\n\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n var getSyncData = function getSyncData() {\n room._log('Sending roomSync request');\n\n var roomId = room.roomId;\n var fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise(function (resolve, reject) {\n var now = new Date().getTime();\n var ping = null;\n var sid = setTimeout(function () {\n room.off('data', fn, _this);\n reject('Timeout');\n }, 3000);\n var body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n var fn = function fn(msg) {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, _this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, _this);\n room.sendMessage(room.handleId, {\n body: body\n }).then(fn).catch(function (e) {\n room.off('data', fn, _this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n var clientPaused = function clientPaused() {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n var propagateMasterFunc = function propagateMasterFunc() {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n getHandlers: function getHandlers() {\n return {\n handlePause: function handlePause(event) {\n room._log('handlePause');\n\n _emitter.emit('pause', event);\n },\n handlePlaying: function handlePlaying(event) {\n room._log('handlePlaying');\n\n _emitter.emit('playing', event);\n },\n handleBuffering: function handleBuffering(event) {\n room._log('handleBuffering');\n\n _emitter.emit('buffering', event);\n },\n handleStalled: function handleStalled(event) {\n room._log('handleBuffering');\n\n room._log('handleStalled');\n\n _emitter.emit('buffering', event);\n\n _emitter.emit('stalled', event);\n },\n handleTimeupdate: function handleTimeupdate(event) {\n room._log('handleTimeupdate');\n\n _emitter.emit('timeupdate', event);\n }\n };\n },\n initialize: function initialize() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n playerInterface = _ref2.playerInterface;\n\n _playerInterface = playerInterface;\n _playerInterfaceOptions = _objectSpread(_objectSpread({}, _playerInterfaceOptions), _playerInterface.options || {});\n\n room._log('Interface options passed: ', _playerInterface.options || {});\n\n room._log('All interface options: ', _playerInterfaceOptions);\n\n shouldPropagateMaster = false;\n isPlaying = _playerInterface.isPaused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (shouldPropagateMaster) {\n propagateMasterFunc().catch(function () {});\n }\n\n if (_playerInterface.isPaused === false) {\n _emitter.once('timeupdate', restartSyncLoop);\n }\n\n _emitter.on('buffering', handleBuffering);\n\n _emitter.on('playing', handlePlaying);\n\n _emitter.on('pause', handlePause);\n },\n destroy: function destroy() {\n var _playerInterface2;\n\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n\n if (typeof ((_playerInterface2 = _playerInterface) === null || _playerInterface2 === void 0 ? void 0 : _playerInterface2.destroy) === 'function') {\n var _playerInterface3;\n\n (_playerInterface3 = _playerInterface) === null || _playerInterface3 === void 0 ? void 0 : _playerInterface3.destroy();\n }\n\n _playerInterface = null;\n\n _emitter.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncUniversal);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-universal.js?");
9335
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../wt-utils */ \"./src/modules/wt-utils.js\");\n/* harmony import */ var _wt_emitter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../wt-emitter */ \"./src/modules/wt-emitter.js\");\n\n\n\nconst syncUniversal = function () {\n let {\n room,\n wt,\n roomSession,\n emitter\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n //SYNC VARS\n let _emitter = Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])();\n\n let _playerInterface = null;\n let _playerInterfaceOptions = {\n isLive: true,\n ignoreBufferedTimeRanges: true,\n useSeekBy: false,\n syncBySegments: false,\n disableFastSeek: false\n };\n const syncDefaultWaitTime = 60000;\n const syncShortWaitTime = 10000;\n const maxSyncThreshold = 0.5;\n const maxSyncTries = 3;\n const waitForPlayingEventAfterSeek = 5000;\n let currentSyncRetry = 0;\n let syncWaitId = null;\n let syncNextWaitTime = null;\n let stopFlag = false;\n let isSyncing = false;\n let playbackRate = 2;\n let isPlaying = false;\n let isPreloading = true;\n let isProgrammaticallySeeked = false;\n let shouldPropagateMaster = false;\n\n const startSyncLoop = () => {\n if (!isConnected()) {\n room._log('--- Sync loop will not start due to user not connected yet ---');\n\n return;\n }\n\n if (syncWaitId) {\n room._log('--- Sync loop already running ---');\n\n return;\n }\n\n room._log('--- Sync enabled ---');\n\n stopFlag = false;\n\n const loop = () => {\n isSyncing = true;\n emitter.emit('playerSyncing', true);\n sync().finally(() => {\n isSyncing = false;\n emitter.emit('playerSyncing', false);\n\n if (isConnected() && !stopFlag) {\n syncWaitId = setTimeout(loop, syncNextWaitTime);\n } else {\n room._log('--- Automatic stop due to user not connected or stop flag enabled ---');\n\n stopSyncLoop();\n }\n });\n };\n\n loop();\n };\n\n const stopSyncLoop = () => {\n room._log('--- Sync disabled ---');\n\n clearTimeout(syncWaitId);\n syncWaitId = null;\n currentSyncRetry = 0;\n stopFlag = true;\n };\n\n const restartSyncLoop = () => {\n room._log('--- Sync restarting ---');\n\n stopSyncLoop();\n startSyncLoop();\n };\n\n const setNextWaitTime = function () {\n let didSyncFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n if (!didSyncFail) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n currentSyncRetry++;\n\n if (currentSyncRetry > maxSyncTries) {\n syncNextWaitTime = syncDefaultWaitTime;\n currentSyncRetry = 0;\n } else {\n syncNextWaitTime = syncShortWaitTime;\n }\n }\n\n room._log('--- Next sync will occur in ' + syncNextWaitTime / 1000 + ' seconds ---');\n };\n\n const sync = () => {\n return getSyncData().then(syncData => {\n if (syncData.isMaster) {\n if (_playerInterface.isPaused) _playerInterface.play();\n setNextWaitTime(false);\n return Promise.resolve();\n } else if (shouldPropagateMaster) {\n setNextWaitTime(false);\n return propagateMasterFunc();\n } else {\n const syncStartTime = Date.now();\n const {\n position,\n realPosition,\n isBufferSufficient\n } = calculateSyncDifferenceTime(syncData.masterFragmentSn, syncData.masterFragmentPos, syncData.ping);\n const currentPosition = getCurrentSegmentPosition() / 1000;\n\n if (position && Math.abs(position - currentPosition) <= maxSyncThreshold) {\n room._log(\"We're within max sync threshold, no need to resync now\");\n\n setNextWaitTime(false);\n return Promise.resolve();\n }\n\n if (position !== null) {\n return seekTo(position).then(() => {\n const seekDuration = (Date.now() - syncStartTime) / 1000;\n const syncPrecision = Math.abs(realPosition + seekDuration - getCurrentSegmentPosition() / 1000);\n\n room._log(realPosition, seekDuration, getCurrentSegmentPosition());\n\n room._log(\"Insufficient buffer: \", !isBufferSufficient);\n\n room._log(\"Seek duration is \".concat(seekDuration, \" seconds\"));\n\n room._log(\"Sync precision should be \".concat(syncPrecision));\n\n const didSyncFail = syncPrecision > maxSyncThreshold;\n setNextWaitTime(didSyncFail);\n return Promise.resolve();\n }).catch(e => {\n setNextWaitTime(true);\n return Promise.reject(e);\n });\n } else {\n setNextWaitTime(true);\n return Promise.reject();\n }\n }\n }).catch(() => {\n setNextWaitTime(true);\n return Promise.reject();\n });\n };\n\n const handleAddLocalParticipant = () => {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n\n if (_playerInterface.isPaused === false) {\n _emitter.once('timeupdate', restartSyncLoop);\n }\n };\n\n const handleAddRemoteParticipant = () => {\n if (shouldPropagateMaster) {\n propagateMasterFunc();\n }\n };\n\n const isConnected = () => {\n return room._isDataChannelOpen && room._hasJoined;\n };\n\n const parseDataEvents = function () {\n let 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(() => {});\n }\n };\n\n const getCurrentSegmentPosition = () => {\n let position = _playerInterface.currentTime;\n return isNaN(position) ? 0 : position * 1000;\n };\n\n const calculateSyncDifferenceTime = (fragmentSn, fragmentPos, ping) => {\n let seekRanges = _playerInterface.buffered;\n let position = (fragmentPos + ping / 2) / 1000;\n\n if (seekRanges && !_playerInterfaceOptions.ignoreBufferedTimeRanges) {\n let seekRange = {};\n\n for (let i = 0; i < seekRanges.length; i++) {\n let _c_start = seekRanges.start(i);\n\n let _c_end = seekRanges.end(i);\n\n if (!seekRange.start || _c_start < seekRange.start) {\n seekRange.start = _c_start;\n }\n\n if (!seekRange.end || _c_end > seekRange.end) {\n seekRange.end = _c_end;\n }\n }\n\n if (position > seekRange.start && position < seekRange.end) {\n return {\n position,\n realPosition: position,\n isBufferSufficient: true\n };\n } else if (position < seekRange.start) {\n room._log(\"Syncing to \".concat(seekRange.start, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.start + 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else if (position > seekRange.end) {\n room._log(\"Syncing to \".concat(seekRange.end, \" instead of \").concat(position, \" due to lack of buffered data\"));\n\n return {\n position: seekRange.end - 0.5,\n realPosition: position,\n isBufferSufficient: false\n };\n } else return {\n position: null,\n isBufferSufficient: false\n };\n } else {\n return {\n position,\n realPosition: position,\n isBufferSufficient: true\n };\n }\n };\n\n const seekTo = time => {\n return new Promise((resolve, reject) => {\n if (_playerInterface.currentTime !== time) {\n let diff = time - _playerInterface.currentTime;\n\n if (_playerInterface.currentTime < time && diff < 4) {\n room._log(\"Fast forward to seek...\");\n\n let wasPaused = false;\n\n let _handleFailed = () => {\n if (wasPaused) {\n _playerInterface.pause();\n }\n\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n reject('Stalled');\n };\n\n let _fastForward = () => {\n isProgrammaticallySeeked = true;\n Object(_wt_utils__WEBPACK_IMPORTED_MODULE_0__[\"setExactTimeout\"])(() => {\n _emitter.off('stalled', _handleFailed);\n\n if (wasPaused && !_playerInterfaceOptions.isLive) {\n _playerInterface.pause();\n }\n\n _playerInterface.setPlaybackRate(1);\n\n isProgrammaticallySeeked = false;\n resolve();\n }, diff * 1000 / (playbackRate - 1), 20);\n\n _playerInterface.setPlaybackRate(playbackRate);\n };\n\n _emitter.once('stalled', _handleFailed);\n\n if (_playerInterface.isPaused) {\n wasPaused = true;\n\n _playerInterface.play().then(() => {\n _fastForward();\n }).catch(_handleFailed);\n } else {\n _fastForward();\n }\n } else {\n room._log(\"Jump to seek...\");\n\n let currentTimestamp = Date.now();\n let __failsafeId = null;\n\n let _resolve = () => {\n clearTimeout(__failsafeId);\n __failsafeId = null;\n isProgrammaticallySeeked = false;\n\n room._log(\"It took the player \".concat((Date.now() - currentTimestamp) / 1000, \" seconds to seek \"));\n\n resolve();\n };\n\n isProgrammaticallySeeked = true; // we need to ignore stall events since those are false alarm\n\n _emitter.once('playing', _resolve);\n\n __failsafeId = setTimeout(_resolve, waitForPlayingEventAfterSeek);\n\n _playerInterface.seek(time);\n }\n } else resolve();\n });\n };\n\n const handlePlaying = () => {\n if (!isProgrammaticallySeeked) {\n room._log('Handle playing');\n\n startSyncLoop();\n }\n\n isProgrammaticallySeeked = false;\n isPreloading = _playerInterface.isPaused;\n isPlaying = !_playerInterface.isPaused;\n };\n\n const handlePause = () => {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPlaying = !_playerInterface.isPaused;\n };\n\n const handleBuffering = () => {\n room._log('handleBuffering');\n\n if (!isProgrammaticallySeeked) {\n stopSyncLoop();\n clientPaused().catch(() => {});\n isPreloading = _playerInterface.isPaused;\n }\n };\n\n const roomSyncSend = slaveId => {\n if (!_playerInterface) {\n room._log(\"I've been asked for position even if we don't have player attached.\\n Does it mean I'm the master?\");\n\n return Promise.resolve();\n }\n\n let fragmentPosition = parseInt(getCurrentSegmentPosition());\n\n room._log(\"Sending my position to \".concat(slaveId));\n\n room._log(\"Current time: \".concat(fragmentPosition));\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_response\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition),\n slave_id: room.webrtcVersion > 1000 ? String(slaveId) : Number(slaveId)\n }\n });\n };\n\n const getSyncData = () => {\n room._log('Sending roomSync request');\n\n let roomId = room.roomId;\n let fragmentPosition = parseInt(getCurrentSegmentPosition());\n return new Promise((resolve, reject) => {\n let now = new Date().getTime();\n let ping = null;\n let sid = setTimeout(() => {\n room.off('data', fn, this);\n reject('Timeout');\n }, 3000);\n let body = {\n request: \"sync\",\n room: roomId,\n timestamp: new Date().getTime(),\n fragment: String(\"0\"),\n fragment_pos: Number(fragmentPosition)\n };\n\n let fn = msg => {\n if (msg.videoroom && ['sync', 'sync_response'].includes(msg.videoroom)) {\n if (msg.sync_master_await) {\n room._log('Waiting for master position');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n } else if (msg.sync_master_fragment || msg.sync_master_fragment_pos) {\n room._log('Got master position data');\n\n if (!ping) {\n ping = new Date().getTime() - now;\n }\n\n room._log(\"I'm master: \".concat(!!msg.sync_master_self));\n\n room._log(\"Ping: \".concat(ping));\n\n room._log(\"Master fragment: \".concat(msg.sync_master_fragment));\n\n room._log(\"Master fragment position: \".concat(msg.sync_master_fragment_pos));\n\n room.off('data', fn, this);\n clearTimeout(sid);\n resolve({\n isMaster: !!msg.sync_master_self,\n ping: ping,\n masterFragmentPos: parseInt(msg.sync_master_fragment_pos),\n masterFragmentSn: parseInt(msg.sync_master_fragment)\n });\n } else {\n clearTimeout(sid);\n reject('Master lost connection');\n }\n }\n };\n\n room.on('data', fn, this);\n room.sendMessage(room.handleId, {\n body\n }).then(fn).catch(e => {\n room.off('data', fn, this);\n clearTimeout(sid);\n reject(e);\n });\n });\n };\n\n const clientPaused = () => {\n room._log('Sending client paused');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_paused\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n fragment: '0',\n fragment_pos: 0\n }\n });\n };\n\n const propagateMasterFunc = () => {\n room._log('Propagating master');\n\n if (!isConnected()) {\n return Promise.resolve();\n }\n\n return room.sendMessage(room.handleId, {\n body: {\n request: \"sync_source_set\",\n room: room.roomId,\n timestamp: new Date().getTime(),\n wt_channel_id: \"\",\n fragment: \"0\",\n fragment_pos: 0\n }\n });\n };\n\n return {\n __events: ['playerSyncing'],\n getHandlers: () => ({\n handlePause: event => {\n room._log('handlePause');\n\n _emitter.emit('pause', event);\n },\n handlePlaying: event => {\n room._log('handlePlaying');\n\n _emitter.emit('playing', event);\n },\n handleBuffering: event => {\n room._log('handleBuffering');\n\n _emitter.emit('buffering', event);\n },\n handleStalled: event => {\n room._log('handleBuffering');\n\n room._log('handleStalled');\n\n _emitter.emit('buffering', event);\n\n _emitter.emit('stalled', event);\n },\n handleTimeupdate: event => {\n room._log('handleTimeupdate');\n\n _emitter.emit('timeupdate', event);\n }\n }),\n initialize: function () {\n let {\n playerInterface\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _playerInterface = playerInterface;\n _playerInterfaceOptions = { ..._playerInterfaceOptions,\n ...(_playerInterface.options || {})\n };\n\n room._log('Interface options passed: ', _playerInterface.options || {});\n\n room._log('All interface options: ', _playerInterfaceOptions);\n\n shouldPropagateMaster = false;\n isPlaying = _playerInterface.isPaused === false;\n room.on('disconnect', stopSyncLoop);\n room.on('removeLocalParticipant', stopSyncLoop);\n room.on('addLocalParticipant', handleAddLocalParticipant);\n room.on('addRemoteParticipant', handleAddRemoteParticipant);\n room.on('data', parseDataEvents);\n\n if (shouldPropagateMaster) {\n propagateMasterFunc().catch(() => {});\n }\n\n if (_playerInterface.isPaused === false) {\n _emitter.once('timeupdate', restartSyncLoop);\n }\n\n _emitter.on('buffering', handleBuffering);\n\n _emitter.on('playing', handlePlaying);\n\n _emitter.on('pause', handlePause);\n },\n destroy: () => {\n var _playerInterface2;\n\n stopSyncLoop();\n room.off('disconnect', stopSyncLoop);\n room.off('removeLocalParticipant', stopSyncLoop);\n room.off('addLocalParticipant', handleAddLocalParticipant);\n room.off('addRemoteParticipant', handleAddRemoteParticipant);\n room.off('data', parseDataEvents);\n\n if (typeof ((_playerInterface2 = _playerInterface) === null || _playerInterface2 === void 0 ? void 0 : _playerInterface2.destroy) === 'function') {\n var _playerInterface3;\n\n (_playerInterface3 = _playerInterface) === null || _playerInterface3 === void 0 ? void 0 : _playerInterface3.destroy();\n }\n\n _playerInterface = null;\n\n _emitter.clear();\n }\n };\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (syncUniversal);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/sync-modules/sync-universal.js?");
9325
9336
 
9326
9337
  /***/ }),
9327
9338
 
@@ -9333,7 +9344,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _wt_
9333
9344
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9334
9345
 
9335
9346
  "use strict";
9336
- eval("__webpack_require__.r(__webpack_exports__);\n/* WEBPACK VAR INJECTION */(function(Buffer) {/* harmony import */ var swagger_client__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! swagger-client */ \"./node_modules/swagger-client/es/index.js\");\n/* harmony import */ var _wt_config__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./wt-config */ \"./src/modules/wt-config.js\");\n/* harmony import */ var _wt_emitter__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./wt-emitter */ \"./src/modules/wt-emitter.js\");\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }, _typeof(obj); }\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\n\n\n\n\nvar Auth = /*#__PURE__*/function () {\n function Auth(enableDebugFlag) {\n var language = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'en-GB';\n var storagePrefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : \"\";\n var apiUrl = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;\n\n _classCallCheck(this, Auth);\n\n this.ID_TOKEN = \"\".concat(storagePrefix !== \"\" ? storagePrefix + '_' : '', \"rwt_idToken\");\n this.ACCESS_TOKEN = \"\".concat(storagePrefix !== \"\" ? storagePrefix + '_' : '', \"rwt_accessToken\");\n this.REFRESH_TOKEN = \"\".concat(storagePrefix !== \"\" ? storagePrefix + '_' : '', \"rwt_refreshToken\");\n Object.assign(this, Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_2__[\"default\"])());\n this.__log = Auth.noop;\n\n if (enableDebugFlag) {\n this._enableDebug();\n }\n\n this.__language = language;\n this.__refreshTokenPromise = null;\n this.__isRefreshing = false;\n this.__isLogged = null;\n this.__parsedJwt = null;\n this.__specUrl = apiUrl ? apiUrl : _wt_config__WEBPACK_IMPORTED_MODULE_1__[\"default\"].apiUrl;\n this.__client = this.initialize(true);\n }\n\n _createClass(Auth, [{\n key: \"_enableDebug\",\n value: function _enableDebug() {\n this.__log = console.log.bind(console);\n }\n }, {\n key: \"_requestInterceptor\",\n value: function _requestInterceptor(req) {\n if (!req.headers) {\n req.headers = {};\n }\n\n req.headers['Accept-Language'] = this.__language;\n return req;\n }\n }, {\n key: \"_responseInterceptor\",\n value: function _responseInterceptor(res, req) {\n var _this = this;\n\n if (res.status === 401) {\n if (this.__isLogged) {\n var rt = localStorage.getItem(this.REFRESH_TOKEN);\n this.__refreshTokenPromise = this.__isRefreshing ? this.__refreshTokenPromise : this.__client.then(function (client) {\n _this.__isRefreshing = true;\n return client.apis.auth.refreshToken({}, {\n requestBody: {\n refreshToken: localStorage.getItem(_this.REFRESH_TOKEN)\n }\n });\n }).then(function (r) {\n _this.__isRefreshing = false;\n return _this.login(r.data.idToken, r.data.accessToken, rt, true);\n }).catch(function (e) {\n _this.__isRefreshing = false;\n\n _this.logout();\n\n return Promise.reject(e);\n });\n return this.__refreshTokenPromise.then(function () {\n return swagger_client__WEBPACK_IMPORTED_MODULE_0__[\"default\"].http(_objectSpread(_objectSpread({}, req), {}, {\n headers: _objectSpread(_objectSpread({}, req.headers), {}, {\n Authorization: 'Bearer ' + localStorage.getItem(_this.ID_TOKEN)\n })\n }));\n }).then(function (res) {\n if (_typeof(res.obj) === 'object' && res.obj !== null) {\n res.data = res.obj;\n }\n\n return res;\n });\n }\n }\n\n if (_typeof(res.obj) === 'object' && res.obj !== null) {\n res.data = res.obj;\n }\n\n return res;\n }\n }, {\n key: \"initialize\",\n value: function initialize() {\n var _this2 = this;\n\n var isInitialEvent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n var isReauth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n var idToken = localStorage.getItem(this.ID_TOKEN);\n var authorizations = {};\n\n if (idToken) {\n authorizations['bearer'] = '' + idToken;\n }\n\n this.__isLogged = !!idToken;\n\n var _that = this;\n\n return new swagger_client__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this.__specUrl, {\n authorizations: authorizations,\n requestInterceptor: this._requestInterceptor.bind(this),\n responseInterceptor: function responseInterceptor(res) {\n return _that._responseInterceptor(res, this);\n }\n }).then(function (client) {\n _this2.__isLogged = !!idToken;\n _this2.__parsedJwt = _this2.parseJwt(idToken);\n\n _this2.emit(_this2.__isLogged ? 'login' : 'logout', {\n client: client,\n isInitialEvent: isInitialEvent,\n isLoggedInAsDevice: _this2.isLoggedInAs(_this2.__parsedJwt, 'device'),\n isLoggedInAsObserver: _this2.isLoggedInAs(_this2.__parsedJwt, 'observer'),\n isLoggedInAsInstanceAdmin: _this2.isLoggedInAs(_this2.__parsedJwt, 'instanceAdmin'),\n isLoggedInAsAdmin: _this2.isLoggedInAs(_this2.__parsedJwt, 'admin'),\n domain: _this2.getDomain(_this2.__parsedJwt),\n isReauth: isReauth\n });\n\n return client;\n }).catch(function (e) {\n _this2.__isLogged = false;\n\n _this2.emit('logout', {\n client: null,\n isInitialEvent: isInitialEvent,\n isLoggedInAsDevice: false,\n isLoggedInAsObserver: false,\n isLoggedInAsInstanceAdmin: false,\n isLoggedInAsAdmin: false,\n isReauth: isReauth\n });\n\n return Promise.reject(e);\n });\n }\n }, {\n key: \"login\",\n value: function login(idToken, accessToken, refreshToken) {\n var isReauth = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n localStorage.setItem(this.ID_TOKEN, idToken);\n localStorage.setItem(this.ACCESS_TOKEN, accessToken);\n localStorage.setItem(this.REFRESH_TOKEN, refreshToken);\n return this.__client = this.initialize(false, isReauth);\n }\n }, {\n key: \"logout\",\n value: function logout() {\n localStorage.removeItem(this.ID_TOKEN);\n localStorage.removeItem(this.ACCESS_TOKEN);\n localStorage.removeItem(this.REFRESH_TOKEN);\n return this.__client = this.initialize();\n }\n }, {\n key: \"isLoggedIn\",\n value: function isLoggedIn() {\n return this.__isLogged;\n }\n }, {\n key: \"isLoggedInAs\",\n value: function isLoggedInAs(parsedJwt) {\n var as = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'device';\n parsedJwt = parsedJwt || this.__parsedJwt;\n return !!(parsedJwt && parsedJwt['cognito:groups'] && parsedJwt['cognito:groups'].includes(as));\n }\n }, {\n key: \"setLanguage\",\n value: function setLanguage(language) {\n this.__language = language;\n return this.__language;\n }\n }, {\n key: \"getDomain\",\n value: function getDomain(parsedJwt) {\n parsedJwt = parsedJwt || this.__parsedJwt;\n return parsedJwt['custom:domain'];\n }\n }, {\n key: \"parseJwt\",\n value: function parseJwt(jwt) {\n if (!jwt || typeof jwt !== \"string\") return false;\n var match = jwt.match(/^(([0-9a-zA-Z]*)\\.){2}[\\w-]*$/);\n if (!match || !match[2]) return false;\n\n try {\n match = new Buffer(match[2], 'base64').toString('binary');\n return JSON.parse(match);\n } catch (e) {\n return false;\n }\n }\n }], [{\n key: \"noop\",\n value: function noop() {}\n }]);\n\n return Auth;\n}();\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Auth);\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../node_modules/node-libs-browser/node_modules/buffer/index.js */ \"./node_modules/node-libs-browser/node_modules/buffer/index.js\").Buffer))\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-auth.js?");
9347
+ eval("__webpack_require__.r(__webpack_exports__);\n/* WEBPACK VAR INJECTION */(function(Buffer) {/* harmony import */ var swagger_client__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! swagger-client */ \"./node_modules/swagger-client/es/index.js\");\n/* harmony import */ var _wt_config__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./wt-config */ \"./src/modules/wt-config.js\");\n/* harmony import */ var _wt_emitter__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./wt-emitter */ \"./src/modules/wt-emitter.js\");\n\n\n\n\nclass Auth {\n constructor(enableDebugFlag) {\n let language = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'en-GB';\n let storagePrefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : \"\";\n let apiUrl = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;\n this.ID_TOKEN = \"\".concat(storagePrefix !== \"\" ? storagePrefix + '_' : '', \"rwt_idToken\");\n this.ACCESS_TOKEN = \"\".concat(storagePrefix !== \"\" ? storagePrefix + '_' : '', \"rwt_accessToken\");\n this.REFRESH_TOKEN = \"\".concat(storagePrefix !== \"\" ? storagePrefix + '_' : '', \"rwt_refreshToken\");\n Object.assign(this, Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_2__[\"default\"])());\n this.__log = Auth.noop;\n\n if (enableDebugFlag) {\n this._enableDebug();\n }\n\n this.__language = language;\n this.__refreshTokenPromise = null;\n this.__isRefreshing = false;\n this.__isLogged = null;\n this.__parsedJwt = null;\n this.__specUrl = apiUrl ? apiUrl : _wt_config__WEBPACK_IMPORTED_MODULE_1__[\"default\"].apiUrl;\n this.__client = this.initialize(true);\n }\n\n static noop() {}\n\n _enableDebug() {\n this.__log = console.log.bind(console);\n }\n\n _requestInterceptor(req) {\n if (!req.headers) {\n req.headers = {};\n }\n\n req.headers['Accept-Language'] = this.__language;\n return req;\n }\n\n _responseInterceptor(res, req) {\n if (res.status === 401) {\n if (this.__isLogged) {\n let rt = localStorage.getItem(this.REFRESH_TOKEN);\n this.__refreshTokenPromise = this.__isRefreshing ? this.__refreshTokenPromise : this.__client.then(client => {\n this.__isRefreshing = true;\n return client.apis.auth.refreshToken({}, {\n requestBody: {\n refreshToken: localStorage.getItem(this.REFRESH_TOKEN)\n }\n });\n }).then(r => {\n this.__isRefreshing = false;\n return this.login(r.data.idToken, r.data.accessToken, rt, true);\n }).catch(e => {\n this.__isRefreshing = false;\n this.logout();\n return Promise.reject(e);\n });\n return this.__refreshTokenPromise.then(() => swagger_client__WEBPACK_IMPORTED_MODULE_0__[\"default\"].http({ ...req,\n headers: { ...req.headers,\n Authorization: 'Bearer ' + localStorage.getItem(this.ID_TOKEN)\n }\n })).then(res => {\n if (typeof res.obj === 'object' && res.obj !== null) {\n res.data = res.obj;\n }\n\n return res;\n });\n }\n }\n\n if (typeof res.obj === 'object' && res.obj !== null) {\n res.data = res.obj;\n }\n\n return res;\n }\n\n initialize() {\n let isInitialEvent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n let isReauth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n let idToken = localStorage.getItem(this.ID_TOKEN);\n let authorizations = {};\n\n if (idToken) {\n authorizations['bearer'] = '' + idToken;\n }\n\n this.__isLogged = !!idToken;\n\n let _that = this;\n\n return new swagger_client__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this.__specUrl, {\n authorizations,\n requestInterceptor: this._requestInterceptor.bind(this),\n responseInterceptor: function (res) {\n return _that._responseInterceptor(res, this);\n }\n }).then(client => {\n this.__isLogged = !!idToken;\n this.__parsedJwt = this.parseJwt(idToken);\n this.emit(this.__isLogged ? 'login' : 'logout', {\n client,\n isInitialEvent,\n isLoggedInAsDevice: this.isLoggedInAs(this.__parsedJwt, 'device'),\n isLoggedInAsObserver: this.isLoggedInAs(this.__parsedJwt, 'observer'),\n isLoggedInAsInstanceAdmin: this.isLoggedInAs(this.__parsedJwt, 'instanceAdmin'),\n isLoggedInAsAdmin: this.isLoggedInAs(this.__parsedJwt, 'admin'),\n domain: this.getDomain(this.__parsedJwt),\n isReauth\n });\n return client;\n }).catch(e => {\n this.__isLogged = false;\n this.emit('logout', {\n client: null,\n isInitialEvent,\n isLoggedInAsDevice: false,\n isLoggedInAsObserver: false,\n isLoggedInAsInstanceAdmin: false,\n isLoggedInAsAdmin: false,\n isReauth\n });\n return Promise.reject(e);\n });\n }\n\n login(idToken, accessToken, refreshToken) {\n let isReauth = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n localStorage.setItem(this.ID_TOKEN, idToken);\n localStorage.setItem(this.ACCESS_TOKEN, accessToken);\n localStorage.setItem(this.REFRESH_TOKEN, refreshToken);\n return this.__client = this.initialize(false, isReauth);\n }\n\n logout() {\n localStorage.removeItem(this.ID_TOKEN);\n localStorage.removeItem(this.ACCESS_TOKEN);\n localStorage.removeItem(this.REFRESH_TOKEN);\n return this.__client = this.initialize();\n }\n\n isLoggedIn() {\n return this.__isLogged;\n }\n\n isLoggedInAs(parsedJwt) {\n let as = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'device';\n parsedJwt = parsedJwt || this.__parsedJwt;\n return !!(parsedJwt && parsedJwt['cognito:groups'] && parsedJwt['cognito:groups'].includes(as));\n }\n\n setLanguage(language) {\n this.__language = language;\n return this.__language;\n }\n\n getDomain(parsedJwt) {\n parsedJwt = parsedJwt || this.__parsedJwt;\n return parsedJwt['custom:domain'];\n }\n\n parseJwt(jwt) {\n if (!jwt || typeof jwt !== \"string\") return false;\n let match = jwt.match(/^(([0-9a-zA-Z]*)\\.){2}[\\w-]*$/);\n if (!match || !match[2]) return false;\n\n try {\n match = new Buffer(match[2], 'base64').toString('binary');\n return JSON.parse(match);\n } catch (e) {\n return false;\n }\n }\n\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Auth);\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../node_modules/node-libs-browser/node_modules/buffer/index.js */ \"./node_modules/node-libs-browser/node_modules/buffer/index.js\").Buffer))\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-auth.js?");
9337
9348
 
9338
9349
  /***/ }),
9339
9350
 
@@ -9345,7 +9356,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* WEBPACK VAR INJECTION */(f
9345
9356
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9346
9357
 
9347
9358
  "use strict";
9348
- eval("__webpack_require__.r(__webpack_exports__);\nvar config = {\n apiUrl: 'https://api.reactoo.com/v3/swagger.json',\n devApiUrl: 'https://api.reactoo.com/dev3/swagger.json'\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = (config);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-config.js?");
9359
+ eval("__webpack_require__.r(__webpack_exports__);\nlet config = {\n apiUrl: 'https://api.reactoo.com/v3/swagger.json',\n devApiUrl: 'https://api.reactoo.com/dev3/swagger.json'\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = (config);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-config.js?");
9349
9360
 
9350
9361
  /***/ }),
9351
9362
 
@@ -9357,7 +9368,7 @@ eval("__webpack_require__.r(__webpack_exports__);\nvar config = {\n apiUrl: 'ht
9357
9368
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9358
9369
 
9359
9370
  "use strict";
9360
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__[\"default\"] = (function () {\n var listeners = new Map();\n return {\n emit: function emit(label) {\n var _this = this;\n\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n\n var curListeners = listeners.get(label);\n\n if (curListeners && curListeners.length) {\n curListeners.forEach(function (listener) {\n var _listener$callback;\n\n (_listener$callback = listener.callback).call.apply(_listener$callback, [listener.vm].concat(args));\n\n listener.once && _this.off(label, listener.callback, listener.vm);\n });\n }\n },\n on: function on(key, fn, that) {\n listeners.has(key) || listeners.set(key, []);\n listeners.get(key).push({\n callback: fn,\n vm: that || this\n });\n },\n off: function off(key, fn, that) {\n var _this2 = this;\n\n var lo_listeners = listeners.get(key);\n\n if (lo_listeners && lo_listeners.length) {\n var index = lo_listeners.findIndex(function (listener) {\n return typeof listener.callback === 'function' && listener.callback === fn && listener.vm === (that || _this2);\n });\n\n if (index > -1) {\n lo_listeners.splice(index, 1);\n listeners.set(key, lo_listeners);\n }\n }\n },\n once: function once(key, fn, that) {\n listeners.has(key) || listeners.set(key, []);\n listeners.get(key).push({\n callback: fn,\n vm: that || this,\n once: true\n });\n },\n clear: function clear() {\n listeners.clear();\n }\n };\n});\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-emitter.js?");
9371
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__[\"default\"] = (function () {\n let listeners = new Map();\n return {\n emit(label) {\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n\n let curListeners = listeners.get(label);\n\n if (curListeners && curListeners.length) {\n curListeners.forEach(listener => {\n listener.callback.call(listener.vm, ...args);\n listener.once && this.off(label, listener.callback, listener.vm);\n });\n }\n },\n\n on(key, fn, that) {\n listeners.has(key) || listeners.set(key, []);\n listeners.get(key).push({\n callback: fn,\n vm: that || this\n });\n },\n\n off(key, fn, that) {\n let lo_listeners = listeners.get(key);\n\n if (lo_listeners && lo_listeners.length) {\n let index = lo_listeners.findIndex(listener => typeof listener.callback === 'function' && listener.callback === fn && listener.vm === (that || this));\n\n if (index > -1) {\n lo_listeners.splice(index, 1);\n listeners.set(key, lo_listeners);\n }\n }\n },\n\n once(key, fn, that) {\n listeners.has(key) || listeners.set(key, []);\n listeners.get(key).push({\n callback: fn,\n vm: that || this,\n once: true\n });\n },\n\n clear() {\n listeners.clear();\n }\n\n };\n});\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-emitter.js?");
9361
9372
 
9362
9373
  /***/ }),
9363
9374
 
@@ -9369,7 +9380,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony default export */
9369
9380
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9370
9381
 
9371
9382
  "use strict";
9372
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var aws_iot_device_sdk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! aws-iot-device-sdk */ \"./node_modules/aws-iot-device-sdk/index.js\");\n/* harmony import */ var aws_iot_device_sdk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(aws_iot_device_sdk__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _wt_emitter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./wt-emitter */ \"./src/modules/wt-emitter.js\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }, _typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\n\n\n\nvar Iot = /*#__PURE__*/function () {\n function Iot(enableDebugFlag) {\n _classCallCheck(this, Iot);\n\n Object.assign(this, Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])());\n this.device = null;\n this.decoder = new TextDecoder('utf-8');\n this.connectionActive = false;\n this.log = Iot.noop;\n this.debugFlag = enableDebugFlag;\n this.credentialsExpirationCheckIntervalId = null;\n this.currentCredentialsExpirationStamp = null;\n\n if (enableDebugFlag) {\n this.enableDebug();\n }\n }\n\n _createClass(Iot, [{\n key: \"enableDebug\",\n value: function enableDebug() {\n this.log = console.log.bind(console);\n }\n }, {\n key: \"startCredentialsExpirationCheck\",\n value: function startCredentialsExpirationCheck(expiration) {\n var _this = this;\n\n this.stopCredentialsExpirationCheck();\n this.currentCredentialsExpirationStamp = new Date(expiration).getTime();\n this.credentialsExpirationCheckIntervalId = setInterval(function () {\n var curentTimeStamp = new Date().getTime();\n\n if (_this.currentCredentialsExpirationStamp - curentTimeStamp <= 300000) {\n _this.emit('updateCredentials');\n }\n }, 5000);\n }\n }, {\n key: \"stopCredentialsExpirationCheck\",\n value: function stopCredentialsExpirationCheck() {\n clearInterval(this.credentialsExpirationCheckIntervalId);\n this.credentialsExpirationCheckIntervalId = null;\n }\n }, {\n key: \"updateWebSocketCredentials\",\n value: function updateWebSocketCredentials(accessKeyId, secretAccessKey, sessionToken, expiration) {\n if (this.device) {\n this.device.updateWebSocketCredentials(accessKeyId, secretAccessKey, sessionToken);\n this.startCredentialsExpirationCheck(expiration);\n }\n }\n }, {\n key: \"connect\",\n value: function connect(apiMqttUrl, apiMqttClientId, region, accessKeyId, secretAccessKey, sessionToken, expiration) {\n var _this2 = this;\n\n var forceDisconnect = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false;\n return this.disconnect(forceDisconnect).then(function () {\n return new Promise(function (resolve, reject) {\n _this2.device = Object(aws_iot_device_sdk__WEBPACK_IMPORTED_MODULE_0__[\"device\"])({\n protocol: 'wss',\n clientId: apiMqttClientId,\n region: region,\n host: apiMqttUrl,\n accessKeyId: accessKeyId,\n secretKey: secretAccessKey,\n sessionToken: sessionToken,\n keepalive: 15,\n maximumReconnectTimeMs: 8000,\n enableMetrics: false,\n debug: _this2.debugFlag,\n autoResubscribe: true\n });\n\n _this2.startCredentialsExpirationCheck(expiration);\n\n var __s = function __s() {\n _this2.device.off('connect', __s);\n\n _this2.device.off('error', __e);\n\n resolve(_this2.device);\n };\n\n var __e = function __e(e) {\n _this2.device.off('connect', __s);\n\n _this2.device.off('error', __e);\n\n reject(e);\n };\n\n _this2.device.once('connect', __s);\n\n _this2.device.once('error', __e);\n\n _this2.device.on('message', _this2.__messageCb.bind(_this2));\n\n _this2.device.on('connect', _this2.__connectCb.bind(_this2));\n\n _this2.device.on('reconnect', _this2.__reconnectCb.bind(_this2));\n\n _this2.device.on('error', _this2.__failureCb.bind(_this2));\n\n _this2.device.on('close', _this2.__closeCb.bind(_this2));\n\n _this2.device.on('offline', _this2.__offlineCb.bind(_this2));\n });\n });\n }\n }, {\n key: \"disconnect\",\n value: function disconnect() {\n var _this3 = this;\n\n var force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n this.stopCredentialsExpirationCheck();\n return new Promise(function (resolve, reject) {\n if (!_this3.device) {\n resolve();\n return;\n }\n\n var __i = null;\n\n var __c = function __c() {\n clearTimeout(__i);\n _this3.device = null;\n resolve();\n };\n\n __i = setTimeout(__c, 4000);\n\n _this3.device.off('message', _this3.__messageCb.bind(_this3));\n\n _this3.device.off('connect', _this3.__connectCb.bind(_this3));\n\n _this3.device.off('reconnect', _this3.__reconnectCb.bind(_this3));\n\n _this3.device.off('error', _this3.__failureCb.bind(_this3));\n\n _this3.device.off('close', _this3.__closeCb.bind(_this3));\n\n _this3.device.off('offline', _this3.__offlineCb.bind(_this3));\n\n _this3.device.end(force, __c);\n });\n }\n }, {\n key: \"isConnected\",\n value: function isConnected() {\n return this.connectionActive;\n }\n }, {\n key: \"subscribe\",\n value: function subscribe(topic) {\n return this.device && this.device.subscribe(topic);\n }\n }, {\n key: \"unsubscribe\",\n value: function unsubscribe(topic) {\n return this.device && this.device.unsubscribe(topic);\n }\n }, {\n key: \"send\",\n value: function send(topic, message) {\n var msg = _typeof(message) === 'object' ? JSON.stringify(message) : message;\n return this.device && this.device.publish(topic, msg);\n }\n }, {\n key: \"__reconnectCb\",\n value: function __reconnectCb() {\n this.emit('reconnect');\n }\n }, {\n key: \"__connectCb\",\n value: function __connectCb() {\n this.connectionActive = true;\n this.emit('connect');\n }\n }, {\n key: \"__failureCb\",\n value: function __failureCb(err) {\n this.emit('error', err);\n }\n }, {\n key: \"__closeCb\",\n value: function __closeCb(responseObject) {\n this.connectionActive = false;\n this.emit('close');\n }\n }, {\n key: \"__offlineCb\",\n value: function __offlineCb(responseObject) {\n this.emit('offline');\n }\n }, {\n key: \"__messageCb\",\n value: function __messageCb(t, message, packet) {\n var topic = t.split('/');\n var payload = JSON.parse(this.decoder.decode(message));\n\n if (topic[0] === 'user') {\n // user\n var userId = topic[1].replace(\"_\", ':');\n this.emit('message', _objectSpread(_objectSpread({\n userId: userId\n }, payload), {}, {\n event: payload.event ? \"user:\".concat(payload.event) : 'user'\n }));\n } else if (topic[0] === 'wt') {\n var event = payload.event;\n var roomId = topic[2];\n\n if (topic[1] === 'room') {\n // room\n if (event === 'message' || event === 'template_updated' || event === 'record_start' || event === 'record_stop' || event === 'record_configured' || event === 'record_livestream_available' || event === 'record_livestream_kick' || event === 'user_update_displayname' || event === 'user_update_avatar' || event === 'user_update_customattributes' || event === 'user_update_privateattributes' || event === 'channel_changed' || event === \"instance_homepage_changed\" || event === \"instance_settings_changed\" || event === \"externalmix_changed\" || event === \"video_uploaded\" || event === \"change_user_devices\" || event === \"queue\" || event === \"title_changed\") {\n this.emit('message', _objectSpread(_objectSpread({\n event: event\n }, payload), {}, {\n roomId: roomId\n }));\n } else if (event === 'joined' || event === 'leaving') {\n this.emit('message', _objectSpread(_objectSpread({\n event: event\n }, payload), {}, {\n isObserver: !!payload.isObserver,\n roomId: roomId\n }));\n } else if (event === 'left' || //user removed room a.k.a. left the room\n event === 'kicked' || event === 'banned' || event === 'unbanned' || event === 'approved' || event === 'muted' || event === 'unmuted' || event === 'messageRemoved' || event === 'messageReported' || event === 'chatClear' || event === 'handRaised' || event === 'handLowered' || event === 'handsCleared') {\n this.emit('message', _objectSpread({\n event: event\n }, payload));\n } else if (event === 'volume_set') {\n this.emit('message', _objectSpread({\n event: event\n }, payload));\n }\n } else if (topic[1] === 'instanceroom') {\n // instance\n if (event === 'add_room' || event === 'remove_room' || event === 'set_room' || event === \"instance_homepage_changed\" || event === 'instance_settings_changed') {\n this.emit('message', _objectSpread({\n event: event\n }, payload));\n }\n } else if (topic[1] === 'externalmix') {\n var _event = payload.event;\n this.emit('message', _objectSpread({\n event: _event\n }, payload));\n }\n } else if (topic[0] === 'wtr') {\n var recorderId = topic[1];\n var sessionId = topic[2];\n\n if (topic[3] === 'control') {\n this.emit('message', _objectSpread(_objectSpread({\n event: 'recorder_control'\n }, payload), {}, {\n recorderId: recorderId,\n sessionId: sessionId\n }));\n } // recorder control\n else if (topic[3] === 'monitor') {\n this.emit('message', _objectSpread(_objectSpread({\n event: 'recorder_monitor'\n }, payload), {}, {\n recorderId: recorderId,\n sessionId: sessionId\n }));\n } // recorder monitor\n\n }\n }\n }], [{\n key: \"noop\",\n value: function noop() {}\n }]);\n\n return Iot;\n}();\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Iot);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-iot.js?");
9383
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var aws_iot_device_sdk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! aws-iot-device-sdk */ \"./node_modules/aws-iot-device-sdk/index.js\");\n/* harmony import */ var aws_iot_device_sdk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(aws_iot_device_sdk__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _wt_emitter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./wt-emitter */ \"./src/modules/wt-emitter.js\");\n\n\n\nclass Iot {\n constructor(enableDebugFlag) {\n Object.assign(this, Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])());\n this.device = null;\n this.decoder = new TextDecoder('utf-8');\n this.connectionActive = false;\n this.log = Iot.noop;\n this.debugFlag = enableDebugFlag;\n this.credentialsExpirationCheckIntervalId = null;\n this.currentCredentialsExpirationStamp = null;\n\n if (enableDebugFlag) {\n this.enableDebug();\n }\n }\n\n static noop() {}\n\n enableDebug() {\n this.log = console.log.bind(console);\n }\n\n startCredentialsExpirationCheck(expiration) {\n this.stopCredentialsExpirationCheck();\n this.currentCredentialsExpirationStamp = new Date(expiration).getTime();\n this.credentialsExpirationCheckIntervalId = setInterval(() => {\n const curentTimeStamp = new Date().getTime();\n\n if (this.currentCredentialsExpirationStamp - curentTimeStamp <= 300000) {\n this.emit('updateCredentials');\n }\n }, 5000);\n }\n\n stopCredentialsExpirationCheck() {\n clearInterval(this.credentialsExpirationCheckIntervalId);\n this.credentialsExpirationCheckIntervalId = null;\n }\n\n updateWebSocketCredentials(accessKeyId, secretAccessKey, sessionToken, expiration) {\n if (this.device) {\n this.device.updateWebSocketCredentials(accessKeyId, secretAccessKey, sessionToken);\n this.startCredentialsExpirationCheck(expiration);\n }\n }\n\n connect(apiMqttUrl, apiMqttClientId, region, accessKeyId, secretAccessKey, sessionToken, expiration) {\n let forceDisconnect = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false;\n return this.disconnect(forceDisconnect).then(() => {\n return new Promise((resolve, reject) => {\n this.device = Object(aws_iot_device_sdk__WEBPACK_IMPORTED_MODULE_0__[\"device\"])({\n protocol: 'wss',\n clientId: apiMqttClientId,\n region,\n host: apiMqttUrl,\n accessKeyId: accessKeyId,\n secretKey: secretAccessKey,\n sessionToken: sessionToken,\n keepalive: 15,\n maximumReconnectTimeMs: 8000,\n enableMetrics: false,\n debug: this.debugFlag,\n autoResubscribe: true\n });\n this.startCredentialsExpirationCheck(expiration);\n\n let __s = () => {\n this.device.off('connect', __s);\n this.device.off('error', __e);\n resolve(this.device);\n };\n\n let __e = e => {\n this.device.off('connect', __s);\n this.device.off('error', __e);\n reject(e);\n };\n\n this.device.once('connect', __s);\n this.device.once('error', __e);\n this.device.on('message', this.__messageCb.bind(this));\n this.device.on('connect', this.__connectCb.bind(this));\n this.device.on('reconnect', this.__reconnectCb.bind(this));\n this.device.on('error', this.__failureCb.bind(this));\n this.device.on('close', this.__closeCb.bind(this));\n this.device.on('offline', this.__offlineCb.bind(this));\n });\n });\n }\n\n disconnect() {\n let force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n this.stopCredentialsExpirationCheck();\n return new Promise((resolve, reject) => {\n if (!this.device) {\n resolve();\n return;\n }\n\n let __i = null;\n\n let __c = () => {\n clearTimeout(__i);\n this.device = null;\n resolve();\n };\n\n __i = setTimeout(__c, 4000);\n this.device.off('message', this.__messageCb.bind(this));\n this.device.off('connect', this.__connectCb.bind(this));\n this.device.off('reconnect', this.__reconnectCb.bind(this));\n this.device.off('error', this.__failureCb.bind(this));\n this.device.off('close', this.__closeCb.bind(this));\n this.device.off('offline', this.__offlineCb.bind(this));\n this.device.end(force, __c);\n });\n }\n\n isConnected() {\n return this.connectionActive;\n }\n\n subscribe(topic) {\n return this.device && this.device.subscribe(topic);\n }\n\n unsubscribe(topic) {\n return this.device && this.device.unsubscribe(topic);\n }\n\n send(topic, message) {\n let msg = typeof message === 'object' ? JSON.stringify(message) : message;\n return this.device && this.device.publish(topic, msg);\n }\n\n __reconnectCb() {\n this.emit('reconnect');\n }\n\n __connectCb() {\n this.connectionActive = true;\n this.emit('connect');\n }\n\n __failureCb(err) {\n this.emit('error', err);\n }\n\n __closeCb(responseObject) {\n this.connectionActive = false;\n this.emit('close');\n }\n\n __offlineCb(responseObject) {\n this.emit('offline');\n }\n\n __messageCb(t, message, packet) {\n const topic = t.split('/');\n const payload = JSON.parse(this.decoder.decode(message));\n\n if (topic[0] === 'user') {\n // user\n const userId = topic[1].replace(\"_\", ':');\n this.emit('message', {\n userId,\n ...payload,\n event: payload.event ? \"user:\".concat(payload.event) : 'user'\n });\n } else if (topic[0] === 'wt') {\n const event = payload.event;\n const roomId = topic[2];\n\n if (topic[1] === 'room') {\n // room\n if (event === 'message' || event === 'template_updated' || event === 'record_start' || event === 'record_stop' || event === 'record_configured' || event === 'record_livestream_available' || event === 'record_livestream_kick' || event === 'user_update_displayname' || event === 'user_update_avatar' || event === 'user_update_customattributes' || event === 'user_update_privateattributes' || event === 'channel_changed' || event === \"instance_homepage_changed\" || event === \"instance_settings_changed\" || event === \"externalmix_changed\" || event === \"video_uploaded\" || event === \"change_user_devices\" || event === \"queue\" || event === \"title_changed\") {\n this.emit('message', {\n event,\n ...payload,\n roomId\n });\n } else if (event === 'joined' || event === 'leaving') {\n this.emit('message', {\n event,\n ...payload,\n isObserver: !!payload.isObserver,\n roomId\n });\n } else if (event === 'left' || //user removed room a.k.a. left the room\n event === 'kicked' || event === 'banned' || event === 'unbanned' || event === 'approved' || event === 'muted' || event === 'unmuted' || event === 'messageRemoved' || event === 'messageReported' || event === 'chatClear' || event === 'handRaised' || event === 'handLowered' || event === 'handsCleared') {\n this.emit('message', {\n event,\n ...payload\n });\n } else if (event === 'volume_set') {\n this.emit('message', {\n event,\n ...payload\n });\n }\n } else if (topic[1] === 'instanceroom') {\n // instance\n if (event === 'add_room' || event === 'remove_room' || event === 'set_room' || event === \"instance_homepage_changed\" || event === 'instance_settings_changed') {\n this.emit('message', {\n event,\n ...payload\n });\n }\n } else if (topic[1] === 'externalmix') {\n const event = payload.event;\n this.emit('message', {\n event,\n ...payload\n });\n }\n } else if (topic[0] === 'wtr') {\n const recorderId = topic[1];\n const sessionId = topic[2];\n\n if (topic[3] === 'control') {\n this.emit('message', {\n event: 'recorder_control',\n ...payload,\n recorderId,\n sessionId\n });\n } // recorder control\n else if (topic[3] === 'monitor') {\n this.emit('message', {\n event: 'recorder_monitor',\n ...payload,\n recorderId,\n sessionId\n });\n } // recorder monitor\n\n }\n }\n\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Iot);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-iot.js?");
9373
9384
 
9374
9385
  /***/ }),
9375
9386
 
@@ -9381,7 +9392,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var aws_
9381
9392
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9382
9393
 
9383
9394
  "use strict";
9384
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! webrtc-adapter */ \"./node_modules/webrtc-adapter/src/js/adapter_core.js\");\n/* harmony import */ var _wt_emitter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./wt-emitter */ \"./src/modules/wt-emitter.js\");\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./wt-utils */ \"./src/modules/wt-utils.js\");\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\nfunction _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\n// Watch together janus webrtc library\n\n\n\n\nvar Room = /*#__PURE__*/function () {\n function Room(debug) {\n var _this = this;\n\n _classCallCheck(this, Room);\n\n this.debug = debug;\n this.sessions = [];\n this.safariVp8 = false;\n this.browser = webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser;\n this.browserDetails = webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails;\n this.webrtcSupported = Room.isWebrtcSupported();\n this.safariVp8TestPromise = Room.testSafariVp8();\n this.safariVp8 = null;\n this.safariVp8TestPromise.then(function (safariVp8) {\n _this.safariVp8 = safariVp8;\n }); // Let's get it started\n\n this.whenInitialized = this.initialize();\n }\n\n _createClass(Room, [{\n key: \"initialize\",\n value: function initialize() {\n var _this2 = this;\n\n return this.safariVp8TestPromise.then(function () {\n return _this2;\n });\n }\n }, {\n key: \"createSession\",\n value: function createSession() {\n var constructId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'reactooroom';\n var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n return new RoomSession(constructId, type, _objectSpread({\n debug: this.debug\n }, options));\n }\n }], [{\n key: \"testSafariVp8\",\n value: function testSafariVp8() {\n return new Promise(function (resolve) {\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'safari' && webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.version >= 605) {\n if (RTCRtpSender && RTCRtpSender.getCapabilities && RTCRtpSender.getCapabilities(\"video\") && RTCRtpSender.getCapabilities(\"video\").codecs && RTCRtpSender.getCapabilities(\"video\").codecs.length) {\n var isVp8 = false;\n\n for (var i in RTCRtpSender.getCapabilities(\"video\").codecs) {\n var codec = RTCRtpSender.getCapabilities(\"video\").codecs[i];\n\n if (codec && codec.mimeType && codec.mimeType.toLowerCase() === \"video/vp8\") {\n isVp8 = true;\n break;\n }\n }\n\n resolve(isVp8);\n } else {\n // We do it in a very ugly way, as there's no alternative...\n // We create a PeerConnection to see if VP8 is in an offer\n var testpc = new RTCPeerConnection({}, {});\n testpc.createOffer({\n offerToReceiveVideo: true\n }).then(function (offer) {\n var result = offer.sdp.indexOf(\"VP8\") !== -1;\n testpc.close();\n testpc = null;\n resolve(result);\n });\n }\n } else resolve(false);\n });\n }\n }, {\n key: \"isWebrtcSupported\",\n value: function isWebrtcSupported() {\n return window.RTCPeerConnection !== undefined && window.RTCPeerConnection !== null && navigator.mediaDevices !== undefined && navigator.mediaDevices !== null && navigator.mediaDevices.getUserMedia !== undefined && navigator.mediaDevices.getUserMedia !== null;\n }\n }]);\n\n return Room;\n}();\n\nvar RoomSession = /*#__PURE__*/function () {\n function RoomSession() {\n var constructId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'reactooroom';\n var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n _classCallCheck(this, RoomSession);\n\n Object.assign(this, Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])());\n this.defaultDataChannelLabel = 'JanusDataChannel';\n this.server = null;\n this.iceServers = null;\n this.token = null;\n this.roomId = null;\n this.streamId = null;\n this.pin = null;\n this.userId = null;\n this.sessiontype = type;\n this.initialBitrate = 0; //TODO: remove this\n\n this.isMonitor = false; // currently used just for classroom context so monitor user only subscribes to participants and not trainer (for other monitor this flag is not necessary)\n\n this.recordingFilename = null;\n this.pluginName = RoomSession.sessionTypes[type];\n this.options = options;\n this.id = null;\n this.privateId = null;\n this.constructId = constructId || RoomSession.randomString(16);\n this.sessionId = null;\n this.handleId = null;\n this.ws = null;\n this.isRestarting = false; //TODO: do it better\n // double click prevention\n\n this.connectingPromise = null;\n this.disconnectingPromise = null;\n this._ipv6Support = false;\n this._retries = 0;\n this._maxRetries = 3;\n this._keepAliveId = null;\n this._participants = [];\n this._observerIds = [];\n this._talkbackIds = [];\n this._instuctorId = null;\n this._hasJoined = false;\n this._isStreaming = false;\n this._isPublished = false;\n this._isDataChannelOpen = false;\n this._dataChannelTimeoutId = null;\n this._messageTimeoutId = null;\n this.isAudioMuted = false;\n this.isVideoMuted = false;\n this.isVideoEnabled = false;\n this.isAudioEnabed = false;\n this.isUnifiedPlan = RoomSession.checkUnifiedPlan();\n this.subscriptionRules = _objectSpread(_objectSpread({}, RoomSession.subscriptionRules), this.options.subscriptionRules || {});\n this._log = RoomSession.noop;\n\n if (this.options.debug) {\n this._enableDebug();\n }\n } // Check if this browser supports Unified Plan and transceivers\n // Based on https://codepen.io/anon/pen/ZqLwWV?editors=0010\n\n\n _createClass(RoomSession, [{\n key: \"_participantShouldSubscribe\",\n value: function _participantShouldSubscribe(userId) {\n var allowedObservers = this._observerIds || [];\n var allowedTalkback = this._talkbackIds || [];\n var allowedInstructor = this._instuctorId || null;\n var localUserRole = 'participant';\n\n if (this.isMonitor) {\n localUserRole = 'monitor';\n } else if (allowedObservers.indexOf(this.userId) > -1) {\n localUserRole = 'observer';\n } else if (allowedTalkback.indexOf(this.userId) > -1) {\n localUserRole = 'talkback';\n } else if (this.userId === allowedInstructor) {\n localUserRole = 'instructor';\n }\n\n var remoteUserRole = 'participant';\n\n if (allowedObservers.indexOf(userId) > -1) {\n remoteUserRole = 'observer';\n } else if (allowedTalkback.indexOf(userId) > -1) {\n remoteUserRole = 'talkback';\n } else if (userId === allowedInstructor) {\n remoteUserRole = 'instructor';\n }\n\n var mode = allowedInstructor !== null ? 'videoWall' : 'watchTogether';\n return this.subscriptionRules[localUserRole][mode].indexOf(remoteUserRole) > -1;\n }\n }, {\n key: \"_getAddParticipantEventName\",\n value: function _getAddParticipantEventName(handleId) {\n var handle = this._getHandle(handleId);\n\n if (!handle) {\n this.emit('error', {\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'getParticipantEventName']\n });\n }\n\n var allowedTalkback = this._talkbackIds || [];\n var allowedObservers = this._observerIds || [];\n var allowedInstructor = this._instuctorId || null;\n var eventName = 'addRemoteParticipant';\n\n if (handle.userId === allowedInstructor) {\n eventName = 'addRemoteInstructor';\n }\n\n if (allowedTalkback.indexOf(handle.userId) > -1) {\n eventName = 'addRemoteTalkback';\n }\n\n if (allowedObservers.indexOf(handle.userId) > -1) {\n eventName = 'addRemoteObserver';\n }\n\n return eventName;\n }\n }, {\n key: \"_getRemoveParticipantEventName\",\n value: function _getRemoveParticipantEventName(handleId) {\n var handle = this._getHandle(handleId);\n\n if (!handle) {\n this.emit('error', {\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'getParticipantEventName']\n });\n }\n\n var allowedTalkback = this._talkbackIds || [];\n var allowedObservers = this._observerIds || [];\n var allowedInstructor = this._instuctorId || null;\n var eventName = 'removeRemoteParticipant';\n\n if (handle.userId === allowedInstructor) {\n eventName = 'removeRemoteInstructor';\n }\n\n if (allowedTalkback.indexOf(handle.userId) > -1) {\n eventName = 'removeRemoteTalkback';\n }\n\n if (allowedObservers.indexOf(handle.userId) > -1) {\n eventName = 'removeRemoteObserver';\n }\n\n return eventName;\n }\n }, {\n key: \"sendMessage\",\n value: function sendMessage(handleId) {\n var message = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n body: 'Example Body'\n };\n var dontWait = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n var dontResolveOnAck = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n return this._send(_objectSpread({\n \"janus\": \"message\",\n \"handle_id\": handleId\n }, message), dontWait, dontResolveOnAck).then(function (json) {\n if (json && json[\"janus\"] === \"success\") {\n var plugindata = json[\"plugindata\"] || {};\n var data = plugindata[\"data\"];\n return Promise.resolve(data);\n }\n\n return Promise.resolve();\n }).catch(function (json) {\n if (json && json[\"error\"]) {\n return Promise.reject({\n type: 'warning',\n id: 1,\n message: 'sendMessage failed',\n data: json[\"error\"]\n });\n } else {\n return Promise.reject({\n type: 'warning',\n id: 1,\n message: 'sendMessage failed',\n data: json\n });\n }\n });\n }\n }, {\n key: \"_send\",\n value: function _send() {\n var _this3 = this;\n\n var request = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var ignoreResponse = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n var dontResolveOnAck = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n var transaction = RoomSession.randomString(12);\n\n var requestData = _objectSpread(_objectSpread({}, request), {}, {\n transaction: transaction,\n token: this.token\n }, this.sessionId && {\n 'session_id': this.sessionId\n } || {});\n\n return new Promise(function (resolve, reject) {\n var parseResponse = function parseResponse(event) {\n var json = JSON.parse(event.data);\n var r_transaction = json['transaction'];\n\n if (r_transaction === transaction && (!dontResolveOnAck || json['janus'] !== 'ack')) {\n clearTimeout(_this3._messageTimeoutId);\n\n _this3.ws.removeEventListener('message', parseResponse);\n\n if (json['janus'] === 'error') {\n var _json$error;\n\n if ((json === null || json === void 0 ? void 0 : (_json$error = json.error) === null || _json$error === void 0 ? void 0 : _json$error.code) == 403) {\n _this3.disconnect(true);\n }\n\n reject({\n type: 'error',\n id: 2,\n message: 'send failed',\n data: json,\n requestData: requestData\n });\n } else {\n resolve(json);\n }\n }\n };\n\n if (ignoreResponse) {\n if (_this3.ws && _this3.ws.readyState === 1) {\n _this3.ws.send(JSON.stringify(requestData));\n }\n\n resolve();\n } else {\n if (_this3.ws && _this3.ws.readyState === 1) {\n _this3.ws.addEventListener('message', parseResponse);\n\n _this3._messageTimeoutId = setTimeout(function () {\n _this3.ws.removeEventListener('message', parseResponse);\n\n reject({\n type: 'error',\n id: 3,\n message: 'send timeout',\n data: requestData\n });\n }, 10000);\n\n _this3.ws.send(JSON.stringify(requestData));\n } else {\n reject({\n type: 'warning',\n id: 29,\n message: 'No connection to WebSockets',\n data: requestData\n });\n }\n }\n });\n }\n }, {\n key: \"_connectionClosed\",\n value: function _connectionClosed() {\n var _this4 = this;\n\n if (this.disconnectingPromise || this.connectingPromise) {\n return;\n }\n\n if (this._retries < this._maxRetries) {\n setTimeout(function () {\n _this4._retries++;\n\n _this4._reconnect().catch(function (e) {\n _this4.emit('error', e);\n });\n }, 3000 * this._retries);\n } else {\n if (this.sessiontype === 'reactooroom') {\n this.disconnect(true);\n } else if (this.sessiontype === 'streaming') {\n this.stopStream();\n }\n\n this.emit('error', {\n type: 'error',\n id: 4,\n message: 'Lost connection to WebSockets',\n data: null\n });\n }\n }\n }, {\n key: \"_wipeListeners\",\n value: function _wipeListeners() {\n if (this.ws) {\n this.ws.removeEventListener('close', this.__connectionClosedBoundFn);\n this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);\n }\n }\n }, {\n key: \"_startKeepAlive\",\n value: function _startKeepAlive() {\n var _this5 = this;\n\n this._send({\n \"janus\": \"keepalive\"\n }).then(function (json) {\n if (json[\"janus\"] !== 'ack') {\n _this5.emit('error', {\n type: 'warning',\n id: 5,\n message: 'keepalive response suspicious',\n data: json[\"janus\"]\n });\n }\n }).catch(function (e) {\n _this5.emit('error', {\n type: 'warning',\n id: 6,\n message: 'keepalive dead',\n data: e\n });\n\n _this5._connectionClosed();\n });\n\n this._keepAliveId = setTimeout(function () {\n _this5._startKeepAlive();\n }, 30000);\n }\n }, {\n key: \"_stopKeepAlive\",\n value: function _stopKeepAlive() {\n clearTimeout(this._keepAliveId);\n }\n }, {\n key: \"_handleWsEvents\",\n value: function _handleWsEvents(event) {\n var _this6 = this;\n\n var json = JSON.parse(event.data);\n var sender = json[\"sender\"];\n var type = json[\"janus\"];\n\n var handle = this._getHandle(sender);\n\n if (!handle) {\n return;\n }\n\n if (type === \"trickle\") {\n var candidate = json[\"candidate\"];\n var config = handle.webrtcStuff;\n\n if (config.pc && config.remoteSdp) {\n if (!candidate || candidate.completed === true) {\n config.pc.addIceCandidate(null);\n } else {\n config.pc.addIceCandidate(candidate);\n }\n } else {\n if (!config.candidates) {\n config.candidates = [];\n }\n\n config.candidates.push(candidate);\n }\n } else if (type === \"webrtcup\") {//none universal\n } else if (type === \"hangup\") {\n this._log('hangup on', handle.handleId);\n\n this._removeParticipant(handle.handleId, null, false);\n } else if (type === \"detached\") {\n this._log('detached on', handle.handleId);\n\n this._removeParticipant(handle.handleId, null, true);\n } else if (type === \"media\") {\n this._log('Media event:', handle.handleId, json[\"type\"], json[\"receiving\"], json[\"mid\"]);\n } else if (type === \"slowlink\") {\n this._log('Slowlink', handle.handleId, json[\"uplink\"], json[\"lost\"], json[\"mid\"]);\n } else if (type === \"event\") {//none universal\n } else if (type === 'timeout') {\n this.ws.close(3504, \"Gateway timeout\");\n } else if (type === 'success' || type === 'error') {// we're capturing those elsewhere\n } else {\n this._log(\"Unknown event: \".concat(type, \" on session: \").concat(this.sessionId));\n } // LOCAL\n\n\n if (sender === this.handleId) {\n if (type === \"event\") {\n var plugindata = json[\"plugindata\"] || {};\n var msg = plugindata[\"data\"] || {};\n var jsep = json[\"jsep\"];\n var result = msg[\"result\"] || null;\n\n var _event = msg[\"videoroom\"] || null;\n\n var list = msg[\"publishers\"] || {};\n var leaving = msg[\"leaving\"]; //let joining = msg[\"joining\"];\n\n var unpublished = msg[\"unpublished\"];\n var error = msg[\"error\"];\n\n if (_event === \"joined\") {\n this.id = msg[\"id\"];\n this.privateId = msg[\"private_id\"];\n this._hasJoined = true;\n this.emit('joined', true);\n\n this._log('We have successfully joined Room');\n\n var _loop = function _loop(f) {\n var userId = list[f][\"display\"];\n var streams = list[f][\"streams\"] || [];\n var id = list[f][\"id\"];\n\n for (var i in streams) {\n streams[i][\"id\"] = id;\n streams[i][\"display\"] = userId;\n }\n\n _this6._log('Remote userId: ', userId);\n\n if (_this6._participantShouldSubscribe(userId)) {\n _this6._log('Creating user: ', userId);\n\n _this6._createParticipant(userId, id).then(function (handle) {\n return _this6.sendMessage(handle.handleId, {\n body: _objectSpread(_objectSpread({\n \"request\": \"join\",\n \"room\": _this6.roomId,\n \"ptype\": \"subscriber\",\n \"feed\": id,\n \"private_id\": _this6.privateId\n }, _this6.webrtcVersion > 1000 ? {\n id: _this6.userId\n } : {}), {}, {\n pin: _this6.pin\n })\n });\n }).catch(function (err) {\n _this6.emit('error', err);\n });\n }\n };\n\n for (var f in list) {\n _loop(f);\n }\n } else if (_event === \"event\") {\n if (msg[\"streams\"] !== undefined && msg[\"streams\"] !== null) {\n this._log('Got my own streams back', msg[\"streams\"]);\n }\n\n var _loop2 = function _loop2(_f) {\n var userId = list[_f][\"display\"];\n var streams = list[_f][\"streams\"] || [];\n var id = list[_f][\"id\"];\n\n for (var i in streams) {\n streams[i][\"id\"] = id;\n streams[i][\"display\"] = userId;\n }\n\n _this6._log('Remote userId: ', userId);\n\n if (_this6._participantShouldSubscribe(userId)) {\n _this6._log('Creating user: ', userId);\n\n _this6._createParticipant(userId, id).then(function (handle) {\n return _this6.sendMessage(handle.handleId, {\n body: _objectSpread(_objectSpread({\n \"request\": \"join\",\n \"room\": _this6.roomId,\n \"ptype\": \"subscriber\",\n \"feed\": id,\n \"private_id\": _this6.privateId\n }, _this6.webrtcVersion > 1000 ? {\n id: _this6.userId\n } : {}), {}, {\n pin: _this6.pin\n })\n });\n }).catch(function (err) {\n _this6.emit('error', err);\n });\n }\n };\n\n for (var _f in list) {\n _loop2(_f);\n }\n\n if (leaving === 'ok') {\n this._log('leaving', this.handleId, 'this is us');\n\n this._removeParticipant(this.handleId);\n\n if (msg['reason'] === 'kicked') {\n this.emit('kicked');\n this.disconnect().catch(function () {});\n }\n } else if (leaving) {\n this._log('leaving', leaving);\n\n this._removeParticipant(null, leaving);\n }\n\n if (unpublished === 'ok') {\n this._log('unpublished', this.handleId, 'this is us');\n\n this._removeParticipant(this.handleId, null, false); // we do just hangup\n\n } else if (unpublished) {\n this._log('unpublished', unpublished);\n\n this._removeParticipant(null, unpublished, true); // we do hangup and detach\n\n }\n\n if (error) {\n this.emit('error', {\n type: 'error',\n id: 7,\n message: 'local participant error',\n data: [sender, msg]\n });\n }\n } // Streaming related\n else if (result && result[\"status\"]) {\n this.emit('streamingStatus', result[\"status\"]);\n\n if (result[\"status\"] === 'stopped') {\n this.stopStream();\n }\n\n if (result[\"status\"] === 'started') {\n this.emit('streaming', true);\n this._isStreaming = true;\n }\n }\n\n if (jsep !== undefined && jsep !== null) {\n if (this.sessiontype === 'reactooroom') {\n this._webrtcPeer(this.handleId, jsep).catch(function (err) {\n _this6.emit('error', err);\n });\n } else if (this.sessiontype === 'streaming') {\n this._publishRemote(this.handleId, jsep).catch(function (err) {\n _this6.emit('error', err);\n });\n }\n }\n } else if (type === \"webrtcup\") {\n this._log('Configuring bitrate: ' + this.initialBitrate);\n\n if (this.initialBitrate > 0) {\n this.sendMessage(this.handleId, {\n \"body\": {\n \"request\": \"configure\",\n \"bitrate\": this.initialBitrate\n }\n }).catch(function () {\n return null;\n });\n }\n }\n } //REMOTE\n else {\n var _plugindata = json[\"plugindata\"] || {};\n\n var _msg = _plugindata[\"data\"] || {};\n\n var _jsep2 = json[\"jsep\"];\n var _event2 = _msg[\"videoroom\"];\n var _error = _msg[\"error\"];\n\n if (_event2 === \"attached\") {\n this._log('Remote have successfully joined Room', _msg);\n\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n stream: null,\n track: null,\n adding: false,\n constructId: this.constructId,\n metaData: this.options.metaData,\n hasAudioTrack: false,\n hasVideoTrack: false\n });\n }\n\n if (_error) {\n this.emit('error', {\n type: 'warning',\n id: 8,\n message: 'remote participant error',\n data: [sender, _msg]\n });\n }\n\n if (_jsep2) {\n this._publishRemote(handle.handleId, _jsep2).catch(function (err) {\n _this6.emit('error', err);\n });\n }\n }\n }\n }, {\n key: \"_handleDataEvents\",\n value: function _handleDataEvents(handleId, type, data) {\n var handle = this._getHandle(handleId);\n\n if (type === 'state') {\n this._log(\" - Data channel status - \", \"UID: \".concat(handleId), \"STATUS: \".concat(JSON.stringify(data)), \"ME: \".concat(handleId === this.handleId));\n\n if (handle) {\n var config = handle.webrtcStuff;\n config.dataChannelOpen = this.defaultDataChannelLabel === (data === null || data === void 0 ? void 0 : data.label) && (data === null || data === void 0 ? void 0 : data.state) === 'open';\n }\n\n if (handleId === this.handleId && this.defaultDataChannelLabel === (data === null || data === void 0 ? void 0 : data.label)) {\n this._isDataChannelOpen = (data === null || data === void 0 ? void 0 : data.state) === 'open';\n this.emit('dataChannel', (data === null || data === void 0 ? void 0 : data.state) === 'open');\n }\n }\n\n if (type === 'error') {\n this.emit('error', {\n type: 'warning',\n id: 9,\n message: 'data event warning',\n data: [handleId, data]\n });\n\n if (handle) {\n var _config = handle.webrtcStuff;\n\n if (this.defaultDataChannelLabel === data.label) {\n _config.dataChannelOpen = false;\n }\n }\n\n if (handleId === this.handleId && this.defaultDataChannelLabel === data.label) {\n this._isDataChannelOpen = false;\n this.emit('dataChannel', false);\n }\n }\n\n if (handleId === this.handleId && type === 'message') {\n var d = null;\n\n try {\n d = JSON.parse(data);\n } catch (e) {\n this.emit('error', {\n type: 'warning',\n id: 10,\n message: 'data message parse error',\n data: [handleId, e]\n });\n return;\n }\n\n this.emit('data', d);\n }\n } //removeHandle === true -> hangup, detach, removeHandle === false -> hangup\n\n }, {\n key: \"_removeParticipant\",\n value: function _removeParticipant(handleId, rfid) {\n var _this7 = this;\n\n var removeHandle = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n\n var handle = this._getHandle(handleId, rfid);\n\n if (!handle) {\n return Promise.resolve();\n } else {\n handleId = handle.handleId;\n }\n\n return this._send({\n \"janus\": \"hangup\",\n \"handle_id\": handleId\n }, true).then(function () {\n return removeHandle ? _this7._send({\n \"janus\": \"detach\",\n \"handle_id\": handleId\n }, true) : Promise.resolve();\n }).finally(function () {\n try {\n if (handle.webrtcStuff.stream && !_this7.isRestarting) {\n handle.webrtcStuff.stream.getTracks().forEach(function (track) {\n return track.stop();\n });\n }\n } catch (e) {// Do nothing\n }\n\n handle.webrtcStuff.stream = null;\n\n if (handle.webrtcStuff.dataChannel) {\n Object.keys(handle.webrtcStuff.dataChannel).forEach(function (label) {\n handle.webrtcStuff.dataChannel[label].onmessage = null;\n handle.webrtcStuff.dataChannel[label].onopen = null;\n handle.webrtcStuff.dataChannel[label].onclose = null;\n handle.webrtcStuff.dataChannel[label].onerror = null;\n });\n }\n\n if (handle.webrtcStuff.pc) {\n handle.webrtcStuff.pc.onicecandidate = null;\n handle.webrtcStuff.pc.ontrack = null;\n handle.webrtcStuff.pc.ondatachannel = null;\n handle.webrtcStuff.pc.onconnectionstatechange = null;\n handle.webrtcStuff.pc.oniceconnectionstatechange = null;\n }\n\n try {\n handle.webrtcStuff.pc.close();\n } catch (e) {}\n\n handle.webrtcStuff = {\n stream: null,\n mySdp: null,\n mediaConstraints: null,\n pc: null,\n dataChannelOpen: false,\n dataChannel: null,\n dtmfSender: null,\n trickle: true,\n iceDone: false\n };\n\n if (handleId === _this7.handleId) {\n _this7._isDataChannelOpen = false;\n _this7._isPublished = false;\n\n _this7.emit('published', {\n status: false,\n hasStream: false\n });\n\n _this7.emit('removeLocalParticipant', {\n id: handleId,\n userId: handle.userId\n });\n } else {\n _this7.emit(_this7._getRemoveParticipantEventName(handleId), {\n id: handleId,\n userId: handle.userId\n });\n }\n\n if (removeHandle) {\n var handleIndex = _this7._participants.findIndex(function (p) {\n return p.handleId === handleId;\n });\n\n _this7._participants.splice(handleIndex, 1);\n }\n\n return true;\n });\n }\n }, {\n key: \"_createParticipant\",\n value: function _createParticipant() {\n var _this8 = this;\n\n var userId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n var rfid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n return this._send({\n \"janus\": \"attach\",\n \"plugin\": this.pluginName\n }).then(function (json) {\n var handleId = json.data[\"id\"];\n var handle = {\n handleId: handleId,\n rfid: rfid,\n userId: userId,\n webrtcStuff: {\n stream: null,\n mySdp: null,\n mediaConstraints: null,\n pc: null,\n dataChannelOpen: false,\n dataChannel: null,\n dtmfSender: null,\n trickle: true,\n iceDone: false,\n isIceRestarting: false\n }\n };\n\n _this8._participants.push(handle);\n\n return handle;\n });\n }\n }, {\n key: \"_joinRoom\",\n value: function _joinRoom(roomId, pin, userId, display) {\n return this.sendMessage(this.handleId, {\n body: _objectSpread({\n \"request\": \"join\",\n \"room\": roomId,\n \"pin\": pin,\n \"ptype\": \"publisher\",\n \"display\": display\n }, this.webrtcVersion > 1000 ? {\n id: userId\n } : {})\n }, false, true);\n }\n }, {\n key: \"_watchStream\",\n value: function _watchStream(id) {\n return this.sendMessage(this.handleId, {\n body: {\n \"request\": \"watch\",\n id: parseInt(id)\n }\n }, false, true);\n }\n }, {\n key: \"_leaveRoom\",\n value: function _leaveRoom() {\n var _this9 = this;\n\n var dontWait = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n return this._hasJoined ? this.sendMessage(this.handleId, {\n body: {\n \"request\": \"leave\"\n }\n }, dontWait).finally(function () {\n _this9._hasJoined = false;\n\n _this9.emit('joined', false);\n }) : Promise.resolve();\n } // internal reconnect\n\n }, {\n key: \"_reconnect\",\n value: function _reconnect() {\n var _this10 = this;\n\n if (this.connectingPromise) {\n return this.connectingPromise;\n }\n\n if (this.ws) {\n this._wipeListeners();\n\n if (this.ws.readyState === 1) {\n this.ws.close();\n }\n }\n\n this._stopKeepAlive();\n\n this.connectingPromise = new Promise(function (resolve, reject) {\n _this10.emit('joining', true);\n\n _this10.ws = new WebSocket(_this10.server, 'janus-protocol');\n _this10.__connectionClosedBoundFn = _this10._connectionClosed.bind(_this10);\n _this10.__handleWsEventsBoundFn = _this10._handleWsEvents.bind(_this10);\n\n _this10.ws.addEventListener('close', _this10.__connectionClosedBoundFn);\n\n _this10.ws.addEventListener('message', _this10.__handleWsEventsBoundFn);\n\n _this10.ws.onopen = function () {\n _this10._send({\n \"janus\": \"claim\"\n }).then(function (json) {\n _this10.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n _this10._startKeepAlive();\n\n _this10.connectingPromise = null;\n\n _this10.emit('joining', false);\n\n _this10._retries = 0;\n resolve(json);\n }).catch(function (error) {\n _this10.connectingPromise = null;\n\n _this10.emit('joining', false);\n\n reject({\n type: 'error',\n id: 11,\n message: 'reconnection error',\n data: error\n });\n });\n }; // this is called before 'close' event callback so it doesn't break reconnect loop\n\n\n _this10.ws.onerror = function (e) {\n _this10.connectingPromise = null;\n\n _this10.emit('joining', false);\n\n reject({\n type: 'warning',\n id: 12,\n message: 'ws reconnection error',\n data: e\n });\n };\n });\n return this.connectingPromise;\n }\n }, {\n key: \"connect\",\n value: function connect(roomId, pin, server, iceServers, token, display, userId) {\n var _this11 = this;\n\n var webrtcVersion = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 0;\n var initialBitrate = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : 0;\n var isMonitor = arguments.length > 9 ? arguments[9] : undefined;\n var recordingFilename = arguments.length > 10 ? arguments[10] : undefined;\n\n if (this.connectingPromise) {\n return this.connectingPromise;\n }\n\n this.emit('joined', false);\n\n if (this.ws) {\n this._wipeListeners();\n }\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = null;\n this.sessionId = null;\n this.server = server;\n this.iceServers = iceServers;\n this.token = token;\n this.roomId = roomId;\n this.pin = pin;\n this.display = display;\n this.userId = userId;\n this.webrtcVersion = webrtcVersion;\n this.initialBitrate = initialBitrate;\n this.isMonitor = isMonitor;\n this.recordingFilename = recordingFilename;\n this.disconnectingPromise = null;\n this.connectingPromise = new Promise(function (resolve, reject) {\n _this11.emit('joining', true);\n\n _this11.ws = new WebSocket(_this11.server, 'janus-protocol');\n _this11.__connectionClosedBoundFn = _this11._connectionClosed.bind(_this11);\n _this11.__handleWsEventsBoundFn = _this11._handleWsEvents.bind(_this11);\n\n _this11.ws.addEventListener('close', _this11.__connectionClosedBoundFn);\n\n _this11.ws.addEventListener('message', _this11.__handleWsEventsBoundFn);\n\n _this11.ws.onopen = function () {\n _this11._retries = 0;\n\n _this11._send({\n \"janus\": \"create\"\n }).then(function (json) {\n _this11.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n _this11._startKeepAlive();\n\n return 1;\n }).then(function () {\n return _this11._createParticipant(userId);\n }).then(function (handle) {\n _this11.handleId = handle.handleId;\n return 1;\n }).then(function () {\n return _this11._joinRoom(roomId, pin, userId, display);\n }).then(function () {\n _this11.connectingPromise = null;\n\n _this11.emit('joining', false);\n\n resolve(_this11);\n }).catch(function (error) {\n _this11.connectingPromise = null;\n\n _this11.emit('joining', false);\n\n reject({\n type: 'error',\n id: 13,\n message: 'connection error',\n data: error\n });\n });\n };\n\n _this11.ws.onerror = function (e) {\n _this11.connectingPromise = null;\n\n _this11.emit('joining', false);\n\n reject({\n type: 'error',\n id: 14,\n message: 'ws connection error',\n data: e\n });\n };\n });\n return this.connectingPromise;\n }\n }, {\n key: \"disconnect\",\n value: function disconnect() {\n var _this12 = this;\n\n if (this.disconnectingPromise) {\n return this.disconnectingPromise;\n }\n\n clearTimeout(this._messageTimeoutId);\n clearTimeout(this._dataChannelTimeoutId);\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = Promise.all(this._participants.map(function (p) {\n return _this12._removeParticipant(p.handleId);\n })).finally(function () {\n _this12._wipeListeners();\n\n if (_this12.ws && _this12.ws.readyState === 1) {\n _this12._send({\n \"janus\": \"destroy\"\n }, true);\n\n _this12.ws.close();\n }\n\n _this12.sessionId = null; //TODO: Just in case something crashed along the way\n\n _this12._isPublished = false;\n _this12._hasJoined = false;\n\n _this12.emit('published', {\n status: false,\n hasStream: false\n });\n\n _this12.emit('joined', false);\n\n _this12.emit('disconnect');\n\n return Promise.resolve('Disconnected');\n });\n return this.disconnectingPromise;\n }\n }, {\n key: \"startStream\",\n value: function startStream(streamId, server, iceServers, token, userId) {\n var _this13 = this;\n\n if (this.connectingPromise) {\n return this.connectingPromise;\n }\n\n this.emit('streaming', false);\n\n if (this.ws) {\n this._wipeListeners();\n }\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = null;\n this.sessionId = null;\n this.server = server;\n this.iceServers = iceServers;\n this.token = token;\n this.streamId = streamId;\n this.userId = userId;\n this.connectingPromise = new Promise(function (resolve, reject) {\n _this13.emit('streamStarting', true);\n\n _this13.ws = new WebSocket(_this13.server, 'janus-protocol');\n _this13.__connectionClosedBoundFn = _this13._connectionClosed.bind(_this13);\n _this13.__handleWsEventsBoundFn = _this13._handleWsEvents.bind(_this13);\n\n _this13.ws.addEventListener('close', _this13.__connectionClosedBoundFn);\n\n _this13.ws.addEventListener('message', _this13.__handleWsEventsBoundFn);\n\n _this13.ws.onopen = function () {\n _this13._retries = 0;\n\n _this13._send({\n \"janus\": \"create\"\n }).then(function (json) {\n _this13.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n _this13._startKeepAlive();\n\n return 1;\n }).then(function () {\n return _this13._createParticipant(userId);\n }).then(function (handle) {\n _this13.handleId = handle.handleId;\n return 1;\n }).then(function () {\n return _this13._watchStream(streamId);\n }).then(function () {\n _this13.connectingPromise = null;\n\n _this13.emit('streamStarting', false);\n\n resolve(_this13);\n }).catch(function (error) {\n _this13.connectingPromise = null;\n\n _this13.emit('streamStarting', false);\n\n reject({\n type: 'error',\n id: 13,\n message: 'connection error',\n data: error\n });\n });\n };\n\n _this13.ws.onerror = function (e) {\n _this13.connectingPromise = null;\n\n _this13.emit('streamStarting', false);\n\n reject({\n type: 'error',\n id: 14,\n message: 'ws connection error',\n data: e\n });\n };\n });\n return this.connectingPromise;\n }\n }, {\n key: \"stopStream\",\n value: function stopStream() {\n var _this14 = this;\n\n if (this.disconnectingPromise) {\n return this.disconnectingPromise;\n }\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = this.sendMessage(this.handleId, {\n body: {\n \"request\": \"stop\"\n }\n }, false, true).then(function () {\n return _this14._removeParticipant(_this14.handleId);\n }).finally(function () {\n _this14._wipeListeners();\n\n _this14._send({\n \"janus\": \"destroy\"\n }, true);\n\n if (_this14.ws && _this14.ws.readyState === 1) {\n _this14.ws.close();\n }\n\n _this14.sessionId = null;\n _this14._isStreaming = false;\n\n _this14.emit('streaming', false); // last event\n\n\n _this14.emit('disconnect');\n\n _this14.disconnectingPromise = null;\n return Promise.resolve('Disconnected');\n });\n return this.disconnectingPromise;\n }\n }, {\n key: \"destroy\",\n value: function destroy() {\n var _this15 = this;\n\n if (this.sessiontype === 'reactooroom') {\n return this.disconnect().then(function () {\n _this15.clear();\n\n return true;\n });\n } else if (this.sessiontype === 'streaming') {\n return this.stopStream().then(function () {\n _this15.clear();\n\n return true;\n });\n }\n }\n }, {\n key: \"_enableDebug\",\n value: function _enableDebug() {\n this._log = console.log.bind(console);\n }\n }, {\n key: \"_getHandle\",\n value: function _getHandle(handleId) {\n var rfid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n return this._participants.find(function (p) {\n return p.handleId === handleId || rfid && p.rfid === rfid;\n });\n }\n }, {\n key: \"_getStats\",\n value: function _getStats() {\n var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n return Promise.all(this._participants.map(function (participant) {\n var mediaTrack = null;\n\n if (type === 'video') {\n mediaTrack = participant.webrtcStuff && participant.webrtcStuff.stream && participant.webrtcStuff.stream.getVideoTracks().length && participant.webrtcStuff.stream.getVideoTracks()[0];\n } else if (type === 'audio') {\n mediaTrack = participant.webrtcStuff && participant.webrtcStuff.stream && participant.webrtcStuff.stream.getAudioTracks().length && participant.webrtcStuff.stream.getAudioTracks()[0];\n }\n\n return participant.webrtcStuff && participant.webrtcStuff.pc && participant.webrtcStuff.pc.getStats(mediaTrack).then(function (r) {\n return {\n handle: participant,\n stats: r\n };\n }).catch(function (e) {\n return Promise.resolve({\n handle: participant,\n stats: e\n });\n });\n }));\n }\n }, {\n key: \"_sendTrickleCandidate\",\n value: function _sendTrickleCandidate(handleId, candidate) {\n return this._send({\n \"janus\": \"trickle\",\n \"candidate\": candidate,\n \"handle_id\": handleId\n });\n }\n }, {\n key: \"_webrtc\",\n value: function _webrtc(handleId) {\n var _this16 = this;\n\n var enableOntrack = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n var handle = this._getHandle(handleId);\n\n if (!handle) {\n this.emit('error', {\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'create rtc connection']\n });\n }\n\n var config = handle.webrtcStuff;\n\n if (!config.pc) {\n var pc_config = {\n \"iceServers\": this.iceServers,\n \"iceTransportPolicy\": 'all',\n \"bundlePolicy\": undefined\n };\n pc_config[\"sdpSemantics\"] = this.isUnifiedPlan ? \"unified-plan\" : \"plan-b\";\n var pc_constraints = {\n \"optional\": [{\n \"DtlsSrtpKeyAgreement\": true\n }]\n };\n\n if (this._ipv6Support === true) {\n pc_constraints.optional.push({\n \"googIPv6\": true\n });\n }\n\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === \"edge\") {\n // This is Edge, enable BUNDLE explicitly\n pc_config.bundlePolicy = \"max-bundle\";\n }\n\n this._log('new RTCPeerConnection', pc_config, pc_constraints);\n\n config.pc = new RTCPeerConnection(pc_config, pc_constraints);\n\n config.pc.onconnectionstatechange = function () {\n if (config.pc.connectionState === 'failed') {\n _this16._iceRestart(handleId);\n }\n\n _this16.emit('connectionState', [handleId, handleId === _this16.handleId, config.pc.connectionState]);\n\n if (handleId !== _this16.handleId && config.pc.connectionState === 'connected') {\n _this16.emit(_this16._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n stream: config.stream,\n track: null,\n optional: true,\n constructId: _this16.constructId,\n metaData: _this16.options.metaData,\n adding: false,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n }\n };\n\n config.pc.oniceconnectionstatechange = function () {\n if (config.pc.iceConnectionState === 'failed') {\n _this16._iceRestart(handleId);\n }\n\n _this16.emit('iceState', [handleId, handleId === _this16.handleId, config.pc.iceConnectionState]);\n\n if (handleId !== _this16.handleId && (config.pc.iceConnectionState === 'completed' || config.pc.iceConnectionState === 'connected')) {\n _this16.emit(_this16._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n stream: config.stream,\n track: null,\n optional: true,\n constructId: _this16.constructId,\n metaData: _this16.options.metaData,\n adding: false,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n }\n };\n\n config.pc.onicecandidate = function (event) {\n if (event.candidate == null || webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'edge' && event.candidate.candidate.indexOf('endOfCandidates') > 0) {\n config.iceDone = true;\n\n _this16._sendTrickleCandidate(handleId, {\n \"completed\": true\n }).catch(function (e) {\n _this16.emit('error', e);\n });\n } else {\n // JSON.stringify doesn't work on some WebRTC objects anymore\n // See https://code.google.com/p/chromium/issues/detail?id=467366\n var candidate = {\n \"candidate\": event.candidate.candidate,\n \"sdpMid\": event.candidate.sdpMid,\n \"sdpMLineIndex\": event.candidate.sdpMLineIndex\n };\n\n _this16._sendTrickleCandidate(handleId, candidate).catch(function (e) {\n _this16.emit('error', e);\n });\n }\n };\n\n if (enableOntrack) {\n config.pc.ontrack = function (event) {\n if (!event.streams) return; //config.stream = event.streams[0];\n\n if (!config.stream) {\n config.stream = new MediaStream();\n }\n\n if (event.track) {\n var mid = event.transceiver ? event.transceiver.mid : event.track.id;\n config.stream.addTrack(event.track);\n\n _this16.emit(_this16._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n mid: mid,\n id: handle.handleId,\n userId: handle.userId,\n stream: config.stream,\n track: event.track,\n constructId: _this16.constructId,\n metaData: _this16.options.metaData,\n adding: true,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n\n if (event.track.onended) return;\n\n event.track.onended = function (ev) {\n var mid = ev.target.id;\n\n if (_this16.isUnifiedPlan) {\n var transceiver = config.pc.getTransceivers().find(function (t) {\n return t.receiver.track === ev.target;\n });\n mid = transceiver.mid;\n }\n\n if (config.stream) {\n config.stream && config.stream.removeTrack(ev.target);\n\n _this16.emit(_this16._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n mid: mid,\n userId: handle.userId,\n stream: config.stream,\n track: ev.target,\n constructId: _this16.constructId,\n metaData: _this16.options.metaData,\n adding: false,\n removing: true,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n }\n };\n\n event.track.onmute = function (ev) {\n _this16._log('remoteTrackMuted', 'onmute');\n\n var mid = ev.target.id;\n\n if (_this16.isUnifiedPlan) {\n var transceiver = config.pc.getTransceivers().find(function (t) {\n return t.receiver.track === ev.target;\n });\n mid = transceiver.mid;\n }\n\n _this16.emit('remoteTrackMuted', {\n id: handle.handleId,\n mid: mid,\n userId: handle.userId,\n stream: config.stream,\n kind: ev.target.kind,\n track: ev.target,\n muted: true\n });\n };\n\n event.track.onunmute = function (ev) {\n _this16._log('remoteTrackMuted', 'onunmute');\n\n var mid = ev.target.id;\n\n if (_this16.isUnifiedPlan) {\n var transceiver = config.pc.getTransceivers().find(function (t) {\n return t.receiver.track === ev.target;\n });\n mid = transceiver.mid;\n }\n\n _this16.emit('remoteTrackMuted', {\n id: handle.handleId,\n mid: mid,\n userId: handle.userId,\n stream: config.stream,\n kind: ev.target.kind,\n track: ev.target,\n muted: false\n });\n };\n }\n };\n }\n }\n\n if (!config.dataChannel || !config.dataChannelOpen) {\n config.dataChannel = {};\n\n var onDataChannelMessage = function onDataChannelMessage(event) {\n _this16._handleDataEvents(handleId, 'message', event.data);\n };\n\n var onDataChannelStateChange = function onDataChannelStateChange(event) {\n var label = event.target.label;\n var protocol = event.target.protocol;\n var state = config.dataChannel[label] ? config.dataChannel[label].readyState : \"null\";\n\n _this16._handleDataEvents(handleId, 'state', {\n state: state,\n label: label\n });\n }; //TODO: check this\n\n\n var onDataChannelError = function onDataChannelError(error) {\n var _error$channel;\n\n _this16._handleDataEvents(handleId, 'error', {\n label: error === null || error === void 0 ? void 0 : (_error$channel = error.channel) === null || _error$channel === void 0 ? void 0 : _error$channel.label,\n error: error\n });\n };\n\n var createDataChannel = function createDataChannel(label, protocol, incoming) {\n var options = {\n ordered: true\n };\n\n if (!incoming) {\n if (protocol) {\n options = _objectSpread(_objectSpread({}, options), {}, {\n protocol: protocol\n });\n }\n\n config.dataChannel[label] = config.pc.createDataChannel(label, options);\n } else {\n config.dataChannel[label] = incoming;\n }\n\n config.dataChannel[label].onmessage = onDataChannelMessage;\n config.dataChannel[label].onopen = onDataChannelStateChange;\n config.dataChannel[label].onclose = onDataChannelStateChange;\n config.dataChannel[label].onerror = onDataChannelError;\n };\n\n createDataChannel(this.defaultDataChannelLabel, null, null);\n\n config.pc.ondatachannel = function (event) {\n createDataChannel(event.channel.label, event.channel.protocol, event.channel);\n };\n }\n }\n }, {\n key: \"_webrtcPeer\",\n value: function _webrtcPeer(handleId, jsep) {\n var handle = this._getHandle(handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'rtc peer']\n });\n }\n\n var config = handle.webrtcStuff;\n\n if (jsep !== undefined && jsep !== null) {\n if (config.pc === null) {\n this._log(\"No PeerConnection: if this is an answer, use createAnswer and not _webrtcPeer\");\n\n return Promise.resolve(null);\n }\n\n return config.pc.setRemoteDescription(jsep).then(function () {\n config.remoteSdp = jsep.sdp; // Any trickle candidate we cached?\n\n if (config.candidates && config.candidates.length > 0) {\n for (var i = 0; i < config.candidates.length; i++) {\n var candidate = config.candidates[i];\n\n if (!candidate || candidate.completed === true) {\n config.pc.addIceCandidate(null);\n } else {\n config.pc.addIceCandidate(candidate);\n }\n }\n\n config.candidates = [];\n } // Done\n\n\n return true;\n });\n } else {\n return Promise.reject({\n type: 'warning',\n id: 22,\n message: 'rtc peer',\n data: [handleId, 'invalid jsep']\n });\n }\n }\n }, {\n key: \"_iceRestart\",\n value: function _iceRestart(handleId) {\n var _this17 = this;\n\n var handle = this._getHandle(handleId);\n\n if (!handle) {\n return;\n }\n\n var config = handle.webrtcStuff; // Already restarting;\n\n if (config.isIceRestarting) {\n return;\n }\n\n if (this.handleId === handleId) {\n this._log('Performing local ICE restart');\n\n config.isIceRestarting = true;\n var hasAudio = !!(config.stream && config.stream.getAudioTracks().length > 0);\n var hasVideo = !!(config.stream && config.stream.getVideoTracks().length > 0);\n\n this._createAO('offer', handleId, true, [hasAudio, false, hasVideo, false]).then(function (jsep) {\n if (!jsep) {\n return null;\n }\n\n return _this17.sendMessage(handleId, {\n body: _objectSpread({\n \"request\": \"configure\",\n \"audio\": hasAudio,\n \"video\": hasVideo,\n \"data\": true\n }, _this17.recordingFilename ? {\n filename: _this17.recordingFilename\n } : {}),\n jsep: jsep\n });\n }).then(function (r) {\n config.isIceRestarting = false;\n\n _this17._log('ICE restart success');\n }).catch(function (e) {\n config.isIceRestarting = false;\n\n _this17.emit('warning', {\n type: 'error',\n id: 28,\n message: 'iceRestart failed',\n data: e\n });\n });\n } else {\n this._log('Performing remote ICE restart', handleId);\n\n config.isIceRestarting = true;\n return this.sendMessage(handleId, {\n body: {\n \"request\": \"configure\",\n \"restart\": true\n }\n }).then(function () {\n config.isIceRestarting = false;\n }).catch(function () {\n config.isIceRestarting = false;\n });\n }\n }\n }, {\n key: \"_createAO\",\n value: function _createAO() {\n var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'offer';\n var handleId = arguments.length > 1 ? arguments[1] : undefined;\n var iceRestart = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n\n var _ref = arguments.length > 3 ? arguments[3] : undefined,\n _ref2 = _slicedToArray(_ref, 4),\n audioSend = _ref2[0],\n audioRecv = _ref2[1],\n videoSend = _ref2[2],\n videoRecv = _ref2[3];\n\n var handle = this._getHandle(handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'createAO', type]\n });\n }\n\n var methodName = null;\n\n if (type === 'offer') {\n methodName = 'createOffer';\n } else {\n methodName = 'createAnswer';\n }\n\n var config = handle.webrtcStuff; // https://code.google.com/p/webrtc/issues/detail?id=3508\n\n var mediaConstraints = {};\n\n if (this.isUnifiedPlan) {\n var audioTransceiver = null,\n videoTransceiver = null;\n var transceivers = config.pc.getTransceivers();\n\n if (transceivers && transceivers.length > 0) {\n for (var i in transceivers) {\n var t = transceivers[i];\n\n if (t.sender && t.sender.track && t.sender.track.kind === \"audio\" && t.stopped === false || t.receiver && t.receiver.track && t.receiver.track.kind === \"audio\" && t.stopped === false) {\n if (!audioTransceiver) audioTransceiver = t;\n continue;\n }\n\n if (t.sender && t.sender.track && t.sender.track.kind === \"video\" && t.stopped === false || t.receiver && t.receiver.track && t.receiver.track.kind === \"video\" && t.stopped === false) {\n if (!videoTransceiver) videoTransceiver = t;\n continue;\n }\n }\n } // Handle audio (and related changes, if any)\n\n\n if (!audioSend && !audioRecv) {\n // Audio disabled: have we removed it?\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"inactive\");\n } else {\n audioTransceiver.direction = \"inactive\";\n }\n }\n } else {\n // Take care of audio m-line\n if (audioSend && audioRecv) {\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"sendrecv\");\n } else {\n audioTransceiver.direction = \"sendrecv\";\n }\n }\n } else if (audioSend && !audioRecv) {\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"sendonly\");\n } else {\n audioTransceiver.direction = \"sendonly\";\n }\n }\n } else if (!audioSend && audioRecv) {\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"recvonly\");\n } else {\n audioTransceiver.direction = \"recvonly\";\n }\n } else {\n // In theory, this is the only case where we might not have a transceiver yet\n audioTransceiver = config.pc.addTransceiver(\"audio\", {\n direction: \"recvonly\"\n });\n }\n }\n } // Handle video (and related changes, if any)\n\n\n if (!videoSend && !videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"inactive\");\n } else {\n videoTransceiver.direction = \"inactive\";\n }\n }\n } else {\n // Take care of video m-line\n if (videoSend && videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"sendrecv\");\n } else {\n videoTransceiver.direction = \"sendrecv\";\n }\n }\n } else if (videoSend && !videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"sendonly\");\n } else {\n videoTransceiver.direction = \"sendonly\";\n }\n }\n } else if (!videoSend && videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"recvonly\");\n } else {\n videoTransceiver.direction = \"recvonly\";\n }\n } else {\n // In theory, this is the only case where we might not have a transceiver yet\n videoTransceiver = config.pc.addTransceiver(\"video\", {\n direction: \"recvonly\"\n });\n }\n }\n }\n } else {\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === \"firefox\" || webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === \"edge\") {\n mediaConstraints = {\n offerToReceiveAudio: audioRecv,\n offerToReceiveVideo: videoRecv\n };\n } else {\n mediaConstraints = {\n mandatory: {\n OfferToReceiveAudio: audioRecv,\n OfferToReceiveVideo: videoRecv\n }\n };\n }\n }\n\n if (iceRestart) {\n mediaConstraints[\"iceRestart\"] = true;\n }\n\n return config.pc[methodName](mediaConstraints).then(function (response) {\n config.mySdp = response.sdp;\n\n var _p = config.pc.setLocalDescription(response).catch(function (e) {\n return Promise.reject({\n type: 'warning',\n id: 24,\n message: 'setLocalDescription',\n data: [handleId, e]\n });\n });\n\n config.mediaConstraints = mediaConstraints;\n\n if (!config.iceDone && !config.trickle) {\n // Don't do anything until we have all candidates\n return Promise.resolve(null);\n } // JSON.stringify doesn't work on some WebRTC objects anymore\n // See https://code.google.com/p/chromium/issues/detail?id=467366\n\n\n var jsep = {\n \"type\": response.type,\n \"sdp\": response.sdp\n };\n return _p.then(function () {\n return jsep;\n });\n }, function (e) {\n return Promise.reject({\n type: 'warning',\n id: 25,\n message: methodName,\n data: [handleId, e]\n });\n });\n }\n }, {\n key: \"_publishRemote\",\n value: function _publishRemote(handleId, jsep) {\n var _this18 = this;\n\n var handle = this._getHandle(handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'publish remote participant']\n });\n }\n\n this._webrtc(handleId, true);\n\n var config = handle.webrtcStuff;\n\n if (jsep) {\n return config.pc.setRemoteDescription(jsep).then(function () {\n config.remoteSdp = jsep.sdp; // Any trickle candidate we cached?\n\n if (config.candidates && config.candidates.length > 0) {\n for (var i = 0; i < config.candidates.length; i++) {\n var candidate = config.candidates[i];\n\n if (!candidate || candidate.completed === true) {\n // end-of-candidates\n config.pc.addIceCandidate(null);\n } else {\n // New candidate\n config.pc.addIceCandidate(candidate);\n }\n }\n\n config.candidates = [];\n } // Create the answer now\n\n\n return _this18._createAO('answer', handleId, false, [false, true, false, true]).then(function (_jsep) {\n if (!_jsep) {\n _this18.emit('error', {\n type: 'warning',\n id: 19,\n message: 'publish remote participant',\n data: [handleId, 'no jsep']\n });\n\n return Promise.resolve();\n }\n\n return _this18.sendMessage(handleId, {\n \"body\": _objectSpread(_objectSpread({\n \"request\": \"start\"\n }, _this18.roomId && {\n \"room\": _this18.roomId\n }), _this18.pin && {\n pin: _this18.pin\n }),\n \"jsep\": _jsep\n });\n });\n }, function (e) {\n return Promise.reject({\n type: 'warning',\n id: 23,\n message: 'setRemoteDescription',\n data: [handleId, e]\n });\n });\n } else {\n return Promise.resolve();\n }\n } //Public methods\n\n }, {\n key: \"publishLocal\",\n value: function publishLocal(stream) {\n var _this19 = this;\n\n var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n _ref3$keepAudio = _ref3.keepAudio,\n keepAudio = _ref3$keepAudio === void 0 ? false : _ref3$keepAudio,\n _ref3$keepVideo = _ref3.keepVideo,\n keepVideo = _ref3$keepVideo === void 0 ? false : _ref3$keepVideo;\n\n this.emit('publishing', true);\n\n var handle = this._getHandle(this.handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'error',\n id: 21,\n message: 'no local id, connect before publishing',\n data: null\n });\n }\n\n this._webrtc(this.handleId);\n\n var config = handle.webrtcStuff;\n\n if (stream) {\n if (!config.stream) {\n config.stream = stream;\n stream.getTracks().forEach(function (track) {\n config.pc.addTrack(track, stream);\n });\n } else {\n /* UPDATE Audio */\n var replaceAudio = stream.getAudioTracks().length;\n\n if (replaceAudio || !keepAudio) {\n //this will stop existing tracks\n var oldAudioStream = config.stream.getAudioTracks()[0];\n\n if (oldAudioStream) {\n config.stream.removeTrack(oldAudioStream);\n\n try {\n oldAudioStream.stop();\n } catch (e) {\n this._log(e);\n }\n }\n }\n\n if (config.pc.getSenders() && config.pc.getSenders().length) {\n if (replaceAudio && this.isUnifiedPlan) {//using replace\n } else {\n for (var index in config.pc.getSenders()) {\n var s = config.pc.getSenders()[index];\n\n if (s && s.track && s.track.kind === \"audio\") {\n config.pc.removeTrack(s);\n }\n }\n }\n }\n\n if (replaceAudio) {\n config.stream.addTrack(stream.getAudioTracks()[0]);\n var audioTransceiver = null;\n\n if (this.isUnifiedPlan) {\n var transceivers = config.pc.getTransceivers();\n\n if (transceivers && transceivers.length > 0) {\n for (var i in transceivers) {\n var t = transceivers[i];\n\n if (t.sender && t.sender.track && t.sender.track.kind === \"audio\" && t.stopped === false || t.receiver && t.receiver.track && t.receiver.track.kind === \"audio\" && t.stopped === false) {\n audioTransceiver = t;\n break;\n }\n }\n }\n }\n\n if (audioTransceiver && audioTransceiver.sender) {\n audioTransceiver.sender.replaceTrack(stream.getAudioTracks()[0]);\n } else {\n config.pc.addTrack(stream.getAudioTracks()[0], stream);\n }\n }\n /* UPDATE Video */\n\n\n var replaceVideo = stream.getVideoTracks().length;\n\n if (replaceVideo || !keepVideo) {\n var oldVideoStream = config.stream.getVideoTracks()[0];\n\n if (oldVideoStream) {\n config.stream.removeTrack(oldVideoStream);\n\n try {\n oldVideoStream.stop();\n } catch (e) {\n this._log(e);\n }\n }\n }\n\n if (config.pc.getSenders() && config.pc.getSenders().length) {\n if (replaceVideo && this.isUnifiedPlan) {//using replace\n } else {\n for (var _index in config.pc.getSenders()) {\n var _s2 = config.pc.getSenders()[_index];\n\n if (_s2 && _s2.track && _s2.track.kind === \"video\") {\n config.pc.removeTrack(_s2);\n }\n }\n }\n }\n\n if (replaceVideo) {\n config.stream.addTrack(stream.getVideoTracks()[0]);\n var videoTransceiver = null;\n\n if (this.isUnifiedPlan) {\n var _transceivers = config.pc.getTransceivers();\n\n if (_transceivers && _transceivers.length > 0) {\n for (var _i2 in _transceivers) {\n var _t = _transceivers[_i2];\n\n if (_t.sender && _t.sender.track && _t.sender.track.kind === \"video\" && _t.stopped === false || _t.receiver && _t.receiver.track && _t.receiver.track.kind === \"video\" && _t.stopped === false) {\n videoTransceiver = _t;\n break;\n }\n }\n }\n }\n\n if (videoTransceiver && videoTransceiver.sender) {\n //TODO: check if t.stopped === false still gets us videoTransceiver\n videoTransceiver.sender.replaceTrack(stream.getVideoTracks()[0]);\n } else {\n config.pc.addTrack(stream.getVideoTracks()[0], stream);\n }\n }\n }\n }\n\n var hasAudio = !!(stream && stream.getAudioTracks().length > 0);\n var hasVideo = !!(stream && stream.getVideoTracks().length > 0);\n var isAudioMuted = !stream || stream.getAudioTracks().length === 0 || !stream.getAudioTracks()[0].enabled;\n var isVideoMuted = !stream || stream.getVideoTracks().length === 0 || !stream.getVideoTracks()[0].enabled;\n this.isAudioEnabed = hasAudio;\n this.isVideoEnabled = hasVideo;\n this.isAudioMuted = isAudioMuted;\n this.isVideoMuted = isVideoMuted;\n return this._createAO('offer', this.handleId, false, [hasAudio, false, hasVideo, false]).then(function (jsep) {\n if (!jsep) {\n return null;\n } //HOTFIX: Temporary fix for Safari 13\n\n\n if (jsep.sdp && jsep.sdp.indexOf(\"\\r\\na=ice-ufrag\") === -1) {\n jsep.sdp = jsep.sdp.replace(\"\\na=ice-ufrag\", \"\\r\\na=ice-ufrag\");\n }\n\n return _this19.sendMessage(_this19.handleId, {\n body: _objectSpread({\n \"request\": \"configure\",\n \"audio\": hasAudio,\n \"video\": hasVideo,\n \"data\": true\n }, _this19.recordingFilename ? {\n filename: _this19.recordingFilename\n } : {}),\n jsep: jsep\n });\n }).then(function (r) {\n if (_this19._isDataChannelOpen) {\n return Promise.resolve(r);\n } else {\n return new Promise(function (resolve, reject) {\n var __ = function __(val) {\n if (val) {\n clearTimeout(_this19._dataChannelTimeoutId);\n\n _this19.off('dataChannel', __, _this19);\n\n resolve(_this19);\n }\n };\n\n _this19._dataChannelTimeoutId = setTimeout(function () {\n _this19.off('dataChannel', __, _this19);\n\n reject({\n type: 'error',\n id: 27,\n message: 'Data channel did not open',\n data: null\n });\n }, 5000);\n\n _this19.on('dataChannel', __, _this19);\n });\n }\n }).then(function (r) {\n _this19._isPublished = true;\n\n if (config.stream) {\n var tracks = config.stream.getTracks();\n tracks.forEach(function (track) {\n // used as a flag to not emit tracks that been already emitted\n if (!track.onended) {\n _this19.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n track: track,\n stream: config.stream,\n adding: true,\n constructId: _this19.constructId,\n metaData: _this19.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n\n track.onended = function (ev) {\n _this19.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n track: ev.target,\n stream: config.stream,\n adding: false,\n removing: true,\n constructId: _this19.constructId,\n metaData: _this19.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n };\n }\n });\n } else {\n _this19.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n stream: null,\n adding: false,\n constructId: _this19.constructId,\n metaData: _this19.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n }\n\n _this19.emit('published', {\n status: true,\n hasStream: !!config.stream\n });\n\n _this19.emit('publishing', false);\n\n _this19.emit('localHasVideo', hasVideo);\n\n _this19.emit('localHasAudio', hasAudio);\n\n _this19.emit('localMuted', {\n type: 'video',\n value: isVideoMuted\n });\n\n _this19.emit('localMuted', {\n type: 'audio',\n value: isAudioMuted\n });\n\n return r;\n }).catch(function (e) {\n _this19.emit('publishing', false);\n\n return Promise.reject(e);\n });\n }\n }, {\n key: \"unpublishLocal\",\n value: function unpublishLocal() {\n var _this20 = this;\n\n var dontWait = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n return this._isPublished ? this.sendMessage(this.handleId, {\n body: {\n \"request\": \"unpublish\"\n }\n }, dontWait).finally(function (r) {\n _this20._isPublished = false;\n\n _this20.emit('published', {\n status: false,\n hasStream: false\n });\n\n return r;\n }) : Promise.resolve();\n }\n }, {\n key: \"toggleAudio\",\n value: function toggleAudio() {\n var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n var mid = arguments.length > 1 ? arguments[1] : undefined;\n\n var handle = this._getHandle(this.handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'error',\n id: 21,\n message: 'no local id, connect first',\n data: null\n });\n }\n\n var config = handle.webrtcStuff;\n\n if (this.isUnifiedPlan) {\n var transceiver = config.pc.getTransceivers().find(function (t) {\n return t.sender && t.sender.track && t.receiver.track.kind === \"audio\" && t.stopped === false && (mid ? t.mid === mid : true);\n });\n\n if (transceiver) {\n transceiver.sender.track.enabled = value !== null ? !!value : !transceiver.sender.track.enabled;\n }\n\n this.isAudioMuted = !transceiver || !transceiver.sender.track.enabled;\n } else {\n if (config.stream && config.stream.getAudioTracks().length) {\n config.stream.getAudioTracks()[0].enabled = value !== null ? !!value : !config.stream.getAudioTracks()[0].enabled;\n }\n\n this.isAudioMuted = config.stream.getAudioTracks().length === 0 || !config.stream.getAudioTracks()[0].enabled;\n }\n\n this.emit('localMuted', {\n type: 'audio',\n value: this.isAudioMuted,\n mid: mid\n });\n }\n }, {\n key: \"toggleVideo\",\n value: function toggleVideo() {\n var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n var mid = arguments.length > 1 ? arguments[1] : undefined;\n\n var handle = this._getHandle(this.handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'error',\n id: 21,\n message: 'no local id, connect first',\n data: null\n });\n }\n\n var config = handle.webrtcStuff;\n\n if (this.isUnifiedPlan) {\n var transceiver = config.pc.getTransceivers().find(function (t) {\n return t.sender && t.sender.track && t.receiver.track.kind === \"video\" && t.stopped === false && (mid ? t.mid === mid : true);\n });\n\n if (transceiver) {\n transceiver.sender.track.enabled = value !== null ? !!value : !transceiver.sender.track.enabled;\n }\n\n this.isVideoMuted = !transceiver || !transceiver.sender.track.enabled;\n } else {\n if (config.stream && config.stream.getVideoTracks().length) {\n config.stream.getVideoTracks()[0].enabled = value !== null ? !!value : !config.stream.getVideoTracks()[0].enabled;\n }\n\n this.isVideoMuted = config.stream.getVideoTracks().length === 0 || !config.stream.getVideoTracks()[0].enabled;\n }\n\n this.emit('localMuted', {\n type: 'video',\n value: this.isVideoMuted,\n mid: mid\n });\n }\n }, {\n key: \"setInstructorId\",\n value: function setInstructorId() {\n var instructorId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n this._instuctorId = instructorId;\n this.emit('instructorId', this._instuctorId);\n return this._instuctorId;\n }\n }, {\n key: \"setObserverIds\",\n value: function setObserverIds() {\n var observerIds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n this._observerIds = observerIds;\n this.emit('observerIds', this._observerIds);\n return this._observerIds;\n }\n }, {\n key: \"setTalkbackIds\",\n value: function setTalkbackIds() {\n var talkbackIds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n this._talkbackIds = talkbackIds;\n this.emit('talkbackIds', this._talkbackIds);\n return this._talkbackIds;\n }\n }], [{\n key: \"noop\",\n value: function noop() {}\n }, {\n key: \"randomString\",\n value: function randomString(len) {\n var charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n var randomString = '';\n\n for (var i = 0; i < len; i++) {\n var randomPoz = Math.floor(Math.random() * charSet.length);\n randomString += charSet.substring(randomPoz, randomPoz + 1);\n }\n\n return randomString;\n } //TODO: solve\n // #eventList = ['error', 'kicked', 'addLocalParticipant', ,'addRemoteInstructor','addRemoteParticipant','addRemoteTalkback', 'addRemoteObserver', 'removeRemoteInstructor', 'removeLocalParticipant', 'removeRemoteParticipant', 'removeRemoteTalkback', 'removeRemoteObserver', 'localMuted', 'localHasVideo', 'localHasAudio', 'data', 'iceState', 'connectionState', 'joined', 'joining', 'dataChannel', 'disconnect', 'observerIds', 'talkbackIds', 'instructorId', 'published', 'publishing', 'remoteTrackMuted', 'streamingStatus', 'streaming', 'streamStarting'];\n //\n\n }, {\n key: \"checkUnifiedPlan\",\n value: function checkUnifiedPlan() {\n var unifiedPlan = false;\n\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'firefox' && webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.version >= 59) {\n // Firefox definitely does, starting from version 59\n unifiedPlan = true;\n } else if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'chrome' && webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.version >= 72) {\n // Chrome does, but it's only usable from version 72 on\n unifiedPlan = true;\n } else if (!window.RTCRtpTransceiver || !('currentDirection' in RTCRtpTransceiver.prototype)) {\n // Safari supports addTransceiver() but not Unified Plan when\n // currentDirection is not defined (see codepen above).\n unifiedPlan = false;\n } else {\n // Check if addTransceiver() throws an exception\n var tempPc = new RTCPeerConnection();\n\n try {\n tempPc.addTransceiver('audio');\n unifiedPlan = true;\n } catch (e) {}\n\n tempPc.close();\n }\n\n return unifiedPlan;\n }\n }]);\n\n return RoomSession;\n}();\n\n_defineProperty(RoomSession, \"sessionTypes\", {\n 'reactooroom': 'janus.plugin.reactooroom',\n 'streaming': 'janus.plugin.streaming'\n});\n\n_defineProperty(RoomSession, \"subscriptionRules\", {\n participant: {\n watchTogether: ['participant', 'talkback'],\n videoWall: ['instructor', 'observer', 'talkback']\n },\n monitor: {\n watchTogether: ['participant'],\n videoWall: ['instructor', 'participant']\n },\n talkback: {\n watchTogether: ['participant'],\n videoWall: ['instructor', 'participant']\n },\n observer: {\n watchTogether: ['participant'],\n videoWall: ['participant']\n },\n instructor: {\n watchTogether: [],\n videoWall: []\n }\n});\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Room);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-room.js?");
9395
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! webrtc-adapter */ \"./node_modules/webrtc-adapter/src/js/adapter_core.js\");\n/* harmony import */ var _wt_emitter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./wt-emitter */ \"./src/modules/wt-emitter.js\");\n/* harmony import */ var _wt_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./wt-utils */ \"./src/modules/wt-utils.js\");\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n// Watch together janus webrtc library\n\n\n\n\nclass Room {\n constructor(debug) {\n this.debug = debug;\n this.sessions = [];\n this.safariVp8 = false;\n this.browser = webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser;\n this.browserDetails = webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails;\n this.webrtcSupported = Room.isWebrtcSupported();\n this.safariVp8TestPromise = Room.testSafariVp8();\n this.safariVp8 = null;\n this.safariVp8TestPromise.then(safariVp8 => {\n this.safariVp8 = safariVp8;\n }); // Let's get it started\n\n this.whenInitialized = this.initialize();\n }\n\n initialize() {\n return this.safariVp8TestPromise.then(() => this);\n }\n\n createSession() {\n let constructId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'reactooroom';\n let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n return new RoomSession(constructId, type, {\n debug: this.debug,\n ...options\n });\n }\n\n static testSafariVp8() {\n return new Promise(resolve => {\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'safari' && webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.version >= 605) {\n if (RTCRtpSender && RTCRtpSender.getCapabilities && RTCRtpSender.getCapabilities(\"video\") && RTCRtpSender.getCapabilities(\"video\").codecs && RTCRtpSender.getCapabilities(\"video\").codecs.length) {\n var isVp8 = false;\n\n for (var i in RTCRtpSender.getCapabilities(\"video\").codecs) {\n var codec = RTCRtpSender.getCapabilities(\"video\").codecs[i];\n\n if (codec && codec.mimeType && codec.mimeType.toLowerCase() === \"video/vp8\") {\n isVp8 = true;\n break;\n }\n }\n\n resolve(isVp8);\n } else {\n // We do it in a very ugly way, as there's no alternative...\n // We create a PeerConnection to see if VP8 is in an offer\n var testpc = new RTCPeerConnection({}, {});\n testpc.createOffer({\n offerToReceiveVideo: true\n }).then(function (offer) {\n let result = offer.sdp.indexOf(\"VP8\") !== -1;\n testpc.close();\n testpc = null;\n resolve(result);\n });\n }\n } else resolve(false);\n });\n }\n\n static isWebrtcSupported() {\n return window.RTCPeerConnection !== undefined && window.RTCPeerConnection !== null && navigator.mediaDevices !== undefined && navigator.mediaDevices !== null && navigator.mediaDevices.getUserMedia !== undefined && navigator.mediaDevices.getUserMedia !== null;\n }\n\n}\n\nclass RoomSession {\n static noop() {}\n\n static randomString(len) {\n var charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n var randomString = '';\n\n for (var i = 0; i < len; i++) {\n var randomPoz = Math.floor(Math.random() * charSet.length);\n randomString += charSet.substring(randomPoz, randomPoz + 1);\n }\n\n return randomString;\n } //TODO: solve\n // #eventList = ['error', 'kicked', 'addLocalParticipant', ,'addRemoteInstructor','addRemoteParticipant','addRemoteTalkback', 'addRemoteObserver', 'removeRemoteInstructor', 'removeLocalParticipant', 'removeRemoteParticipant', 'removeRemoteTalkback', 'removeRemoteObserver', 'localMuted', 'localHasVideo', 'localHasAudio', 'data', 'iceState', 'connectionState', 'joined', 'joining', 'dataChannel', 'disconnect', 'observerIds', 'talkbackIds', 'instructorId', 'published', 'publishing', 'remoteTrackMuted', 'streamingStatus', 'streaming', 'streamStarting'];\n //\n\n\n constructor() {\n let constructId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'reactooroom';\n let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n Object.assign(this, Object(_wt_emitter__WEBPACK_IMPORTED_MODULE_1__[\"default\"])());\n this.defaultDataChannelLabel = 'JanusDataChannel';\n this.server = null;\n this.iceServers = null;\n this.token = null;\n this.roomId = null;\n this.streamId = null;\n this.pin = null;\n this.userId = null;\n this.sessiontype = type;\n this.initialBitrate = 0; //TODO: remove this\n\n this.isMonitor = false; // currently used just for classroom context so monitor user only subscribes to participants and not trainer (for other monitor this flag is not necessary)\n\n this.recordingFilename = null;\n this.pluginName = RoomSession.sessionTypes[type];\n this.options = options;\n this.id = null;\n this.privateId = null;\n this.constructId = constructId || RoomSession.randomString(16);\n this.sessionId = null;\n this.handleId = null;\n this.ws = null;\n this.isRestarting = false; //TODO: do it better\n // double click prevention\n\n this.connectingPromise = null;\n this.disconnectingPromise = null;\n this._ipv6Support = false;\n this._retries = 0;\n this._maxRetries = 3;\n this._keepAliveId = null;\n this._participants = [];\n this._observerIds = [];\n this._talkbackIds = [];\n this._instuctorId = null;\n this._hasJoined = false;\n this._isStreaming = false;\n this._isPublished = false;\n this._isDataChannelOpen = false;\n this._dataChannelTimeoutId = null;\n this._messageTimeoutId = null;\n this.isAudioMuted = false;\n this.isVideoMuted = false;\n this.isVideoEnabled = false;\n this.isAudioEnabed = false;\n this.isUnifiedPlan = RoomSession.checkUnifiedPlan();\n this.subscriptionRules = { ...RoomSession.subscriptionRules,\n ...(this.options.subscriptionRules || {})\n };\n this._log = RoomSession.noop;\n\n if (this.options.debug) {\n this._enableDebug();\n }\n } // Check if this browser supports Unified Plan and transceivers\n // Based on https://codepen.io/anon/pen/ZqLwWV?editors=0010\n\n\n static checkUnifiedPlan() {\n let unifiedPlan = false;\n\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'firefox' && webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.version >= 59) {\n // Firefox definitely does, starting from version 59\n unifiedPlan = true;\n } else if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'chrome' && webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.version >= 72) {\n // Chrome does, but it's only usable from version 72 on\n unifiedPlan = true;\n } else if (!window.RTCRtpTransceiver || !('currentDirection' in RTCRtpTransceiver.prototype)) {\n // Safari supports addTransceiver() but not Unified Plan when\n // currentDirection is not defined (see codepen above).\n unifiedPlan = false;\n } else {\n // Check if addTransceiver() throws an exception\n const tempPc = new RTCPeerConnection();\n\n try {\n tempPc.addTransceiver('audio');\n unifiedPlan = true;\n } catch (e) {}\n\n tempPc.close();\n }\n\n return unifiedPlan;\n }\n\n _participantShouldSubscribe(userId) {\n let allowedObservers = this._observerIds || [];\n let allowedTalkback = this._talkbackIds || [];\n let allowedInstructor = this._instuctorId || null;\n let localUserRole = 'participant';\n\n if (this.isMonitor) {\n localUserRole = 'monitor';\n } else if (allowedObservers.indexOf(this.userId) > -1) {\n localUserRole = 'observer';\n } else if (allowedTalkback.indexOf(this.userId) > -1) {\n localUserRole = 'talkback';\n } else if (this.userId === allowedInstructor) {\n localUserRole = 'instructor';\n }\n\n let remoteUserRole = 'participant';\n\n if (allowedObservers.indexOf(userId) > -1) {\n remoteUserRole = 'observer';\n } else if (allowedTalkback.indexOf(userId) > -1) {\n remoteUserRole = 'talkback';\n } else if (userId === allowedInstructor) {\n remoteUserRole = 'instructor';\n }\n\n let mode = allowedInstructor !== null ? 'videoWall' : 'watchTogether';\n return this.subscriptionRules[localUserRole][mode].indexOf(remoteUserRole) > -1;\n }\n\n _getAddParticipantEventName(handleId) {\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n this.emit('error', {\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'getParticipantEventName']\n });\n }\n\n let allowedTalkback = this._talkbackIds || [];\n let allowedObservers = this._observerIds || [];\n let allowedInstructor = this._instuctorId || null;\n let eventName = 'addRemoteParticipant';\n\n if (handle.userId === allowedInstructor) {\n eventName = 'addRemoteInstructor';\n }\n\n if (allowedTalkback.indexOf(handle.userId) > -1) {\n eventName = 'addRemoteTalkback';\n }\n\n if (allowedObservers.indexOf(handle.userId) > -1) {\n eventName = 'addRemoteObserver';\n }\n\n return eventName;\n }\n\n _getRemoveParticipantEventName(handleId) {\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n this.emit('error', {\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'getParticipantEventName']\n });\n }\n\n let allowedTalkback = this._talkbackIds || [];\n let allowedObservers = this._observerIds || [];\n let allowedInstructor = this._instuctorId || null;\n let eventName = 'removeRemoteParticipant';\n\n if (handle.userId === allowedInstructor) {\n eventName = 'removeRemoteInstructor';\n }\n\n if (allowedTalkback.indexOf(handle.userId) > -1) {\n eventName = 'removeRemoteTalkback';\n }\n\n if (allowedObservers.indexOf(handle.userId) > -1) {\n eventName = 'removeRemoteObserver';\n }\n\n return eventName;\n }\n\n sendMessage(handleId) {\n let message = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n body: 'Example Body'\n };\n let dontWait = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n let dontResolveOnAck = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n return this._send({\n \"janus\": \"message\",\n \"handle_id\": handleId,\n ...message\n }, dontWait, dontResolveOnAck).then(json => {\n if (json && json[\"janus\"] === \"success\") {\n let plugindata = json[\"plugindata\"] || {};\n let data = plugindata[\"data\"];\n return Promise.resolve(data);\n }\n\n return Promise.resolve();\n }).catch(json => {\n if (json && json[\"error\"]) {\n return Promise.reject({\n type: 'warning',\n id: 1,\n message: 'sendMessage failed',\n data: json[\"error\"]\n });\n } else {\n return Promise.reject({\n type: 'warning',\n id: 1,\n message: 'sendMessage failed',\n data: json\n });\n }\n });\n }\n\n _send() {\n let request = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let ignoreResponse = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n let dontResolveOnAck = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n let transaction = RoomSession.randomString(12);\n let requestData = { ...request,\n transaction,\n token: this.token,\n ...(this.sessionId && {\n 'session_id': this.sessionId\n } || {})\n };\n return new Promise((resolve, reject) => {\n let parseResponse = event => {\n let json = JSON.parse(event.data);\n let r_transaction = json['transaction'];\n\n if (r_transaction === transaction && (!dontResolveOnAck || json['janus'] !== 'ack')) {\n clearTimeout(this._messageTimeoutId);\n this.ws.removeEventListener('message', parseResponse);\n\n if (json['janus'] === 'error') {\n var _json$error;\n\n if ((json === null || json === void 0 ? void 0 : (_json$error = json.error) === null || _json$error === void 0 ? void 0 : _json$error.code) == 403) {\n this.disconnect(true);\n }\n\n reject({\n type: 'error',\n id: 2,\n message: 'send failed',\n data: json,\n requestData\n });\n } else {\n resolve(json);\n }\n }\n };\n\n if (ignoreResponse) {\n if (this.ws && this.ws.readyState === 1) {\n this.ws.send(JSON.stringify(requestData));\n }\n\n resolve();\n } else {\n if (this.ws && this.ws.readyState === 1) {\n this.ws.addEventListener('message', parseResponse);\n this._messageTimeoutId = setTimeout(() => {\n this.ws.removeEventListener('message', parseResponse);\n reject({\n type: 'error',\n id: 3,\n message: 'send timeout',\n data: requestData\n });\n }, 10000);\n this.ws.send(JSON.stringify(requestData));\n } else {\n reject({\n type: 'warning',\n id: 29,\n message: 'No connection to WebSockets',\n data: requestData\n });\n }\n }\n });\n }\n\n _connectionClosed() {\n if (this.disconnectingPromise || this.connectingPromise) {\n return;\n }\n\n if (this._retries < this._maxRetries) {\n setTimeout(() => {\n this._retries++;\n\n this._reconnect().catch(e => {\n this.emit('error', e);\n });\n }, 3000 * this._retries);\n } else {\n if (this.sessiontype === 'reactooroom') {\n this.disconnect(true);\n } else if (this.sessiontype === 'streaming') {\n this.stopStream();\n }\n\n this.emit('error', {\n type: 'error',\n id: 4,\n message: 'Lost connection to WebSockets',\n data: null\n });\n }\n }\n\n _wipeListeners() {\n if (this.ws) {\n this.ws.removeEventListener('close', this.__connectionClosedBoundFn);\n this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);\n }\n }\n\n _startKeepAlive() {\n this._send({\n \"janus\": \"keepalive\"\n }).then(json => {\n if (json[\"janus\"] !== 'ack') {\n this.emit('error', {\n type: 'warning',\n id: 5,\n message: 'keepalive response suspicious',\n data: json[\"janus\"]\n });\n }\n }).catch(e => {\n this.emit('error', {\n type: 'warning',\n id: 6,\n message: 'keepalive dead',\n data: e\n });\n\n this._connectionClosed();\n });\n\n this._keepAliveId = setTimeout(() => {\n this._startKeepAlive();\n }, 30000);\n }\n\n _stopKeepAlive() {\n clearTimeout(this._keepAliveId);\n }\n\n _handleWsEvents(event) {\n let json = JSON.parse(event.data);\n var sender = json[\"sender\"];\n var type = json[\"janus\"];\n\n let handle = this._getHandle(sender);\n\n if (!handle) {\n return;\n }\n\n if (type === \"trickle\") {\n let candidate = json[\"candidate\"];\n let config = handle.webrtcStuff;\n\n if (config.pc && config.remoteSdp) {\n if (!candidate || candidate.completed === true) {\n config.pc.addIceCandidate(null);\n } else {\n config.pc.addIceCandidate(candidate);\n }\n } else {\n if (!config.candidates) {\n config.candidates = [];\n }\n\n config.candidates.push(candidate);\n }\n } else if (type === \"webrtcup\") {//none universal\n } else if (type === \"hangup\") {\n this._log('hangup on', handle.handleId);\n\n this._removeParticipant(handle.handleId, null, false);\n } else if (type === \"detached\") {\n this._log('detached on', handle.handleId);\n\n this._removeParticipant(handle.handleId, null, true);\n } else if (type === \"media\") {\n this._log('Media event:', handle.handleId, json[\"type\"], json[\"receiving\"], json[\"mid\"]);\n } else if (type === \"slowlink\") {\n this._log('Slowlink', handle.handleId, json[\"uplink\"], json[\"lost\"], json[\"mid\"]);\n } else if (type === \"event\") {//none universal\n } else if (type === 'timeout') {\n this.ws.close(3504, \"Gateway timeout\");\n } else if (type === 'success' || type === 'error') {// we're capturing those elsewhere\n } else {\n this._log(\"Unknown event: \".concat(type, \" on session: \").concat(this.sessionId));\n } // LOCAL\n\n\n if (sender === this.handleId) {\n if (type === \"event\") {\n var plugindata = json[\"plugindata\"] || {};\n var msg = plugindata[\"data\"] || {};\n var jsep = json[\"jsep\"];\n let result = msg[\"result\"] || null;\n let event = msg[\"videoroom\"] || null;\n let list = msg[\"publishers\"] || {};\n let leaving = msg[\"leaving\"]; //let joining = msg[\"joining\"];\n\n let unpublished = msg[\"unpublished\"];\n let error = msg[\"error\"];\n\n if (event === \"joined\") {\n this.id = msg[\"id\"];\n this.privateId = msg[\"private_id\"];\n this._hasJoined = true;\n this.emit('joined', true);\n\n this._log('We have successfully joined Room');\n\n for (let f in list) {\n let userId = list[f][\"display\"];\n let streams = list[f][\"streams\"] || [];\n let id = list[f][\"id\"];\n\n for (let i in streams) {\n streams[i][\"id\"] = id;\n streams[i][\"display\"] = userId;\n }\n\n this._log('Remote userId: ', userId);\n\n if (this._participantShouldSubscribe(userId)) {\n this._log('Creating user: ', userId);\n\n this._createParticipant(userId, id).then(handle => {\n return this.sendMessage(handle.handleId, {\n body: {\n \"request\": \"join\",\n \"room\": this.roomId,\n \"ptype\": \"subscriber\",\n \"feed\": id,\n \"private_id\": this.privateId,\n ...(this.webrtcVersion > 1000 ? {\n id: this.userId\n } : {}),\n pin: this.pin\n }\n });\n }).catch(err => {\n this.emit('error', err);\n });\n }\n }\n } else if (event === \"event\") {\n if (msg[\"streams\"] !== undefined && msg[\"streams\"] !== null) {\n this._log('Got my own streams back', msg[\"streams\"]);\n }\n\n for (let f in list) {\n let userId = list[f][\"display\"];\n let streams = list[f][\"streams\"] || [];\n let id = list[f][\"id\"];\n\n for (let i in streams) {\n streams[i][\"id\"] = id;\n streams[i][\"display\"] = userId;\n }\n\n this._log('Remote userId: ', userId);\n\n if (this._participantShouldSubscribe(userId)) {\n this._log('Creating user: ', userId);\n\n this._createParticipant(userId, id).then(handle => {\n return this.sendMessage(handle.handleId, {\n body: {\n \"request\": \"join\",\n \"room\": this.roomId,\n \"ptype\": \"subscriber\",\n \"feed\": id,\n \"private_id\": this.privateId,\n ...(this.webrtcVersion > 1000 ? {\n id: this.userId\n } : {}),\n pin: this.pin\n }\n });\n }).catch(err => {\n this.emit('error', err);\n });\n }\n }\n\n if (leaving === 'ok') {\n this._log('leaving', this.handleId, 'this is us');\n\n this._removeParticipant(this.handleId);\n\n if (msg['reason'] === 'kicked') {\n this.emit('kicked');\n this.disconnect().catch(() => {});\n }\n } else if (leaving) {\n this._log('leaving', leaving);\n\n this._removeParticipant(null, leaving);\n }\n\n if (unpublished === 'ok') {\n this._log('unpublished', this.handleId, 'this is us');\n\n this._removeParticipant(this.handleId, null, false); // we do just hangup\n\n } else if (unpublished) {\n this._log('unpublished', unpublished);\n\n this._removeParticipant(null, unpublished, true); // we do hangup and detach\n\n }\n\n if (error) {\n this.emit('error', {\n type: 'error',\n id: 7,\n message: 'local participant error',\n data: [sender, msg]\n });\n }\n } // Streaming related\n else if (result && result[\"status\"]) {\n this.emit('streamingStatus', result[\"status\"]);\n\n if (result[\"status\"] === 'stopped') {\n this.stopStream();\n }\n\n if (result[\"status\"] === 'started') {\n this.emit('streaming', true);\n this._isStreaming = true;\n }\n }\n\n if (jsep !== undefined && jsep !== null) {\n if (this.sessiontype === 'reactooroom') {\n this._webrtcPeer(this.handleId, jsep).catch(err => {\n this.emit('error', err);\n });\n } else if (this.sessiontype === 'streaming') {\n this._publishRemote(this.handleId, jsep).catch(err => {\n this.emit('error', err);\n });\n }\n }\n } else if (type === \"webrtcup\") {\n this._log('Configuring bitrate: ' + this.initialBitrate);\n\n if (this.initialBitrate > 0) {\n this.sendMessage(this.handleId, {\n \"body\": {\n \"request\": \"configure\",\n \"bitrate\": this.initialBitrate\n }\n }).catch(() => null);\n }\n }\n } //REMOTE\n else {\n let plugindata = json[\"plugindata\"] || {};\n let msg = plugindata[\"data\"] || {};\n let jsep = json[\"jsep\"];\n let event = msg[\"videoroom\"];\n let error = msg[\"error\"];\n\n if (event === \"attached\") {\n this._log('Remote have successfully joined Room', msg);\n\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n stream: null,\n track: null,\n adding: false,\n constructId: this.constructId,\n metaData: this.options.metaData,\n hasAudioTrack: false,\n hasVideoTrack: false\n });\n }\n\n if (error) {\n this.emit('error', {\n type: 'warning',\n id: 8,\n message: 'remote participant error',\n data: [sender, msg]\n });\n }\n\n if (jsep) {\n this._publishRemote(handle.handleId, jsep).catch(err => {\n this.emit('error', err);\n });\n }\n }\n }\n\n _handleDataEvents(handleId, type, data) {\n let handle = this._getHandle(handleId);\n\n if (type === 'state') {\n this._log(\" - Data channel status - \", \"UID: \".concat(handleId), \"STATUS: \".concat(JSON.stringify(data)), \"ME: \".concat(handleId === this.handleId));\n\n if (handle) {\n let config = handle.webrtcStuff;\n config.dataChannelOpen = this.defaultDataChannelLabel === (data === null || data === void 0 ? void 0 : data.label) && (data === null || data === void 0 ? void 0 : data.state) === 'open';\n }\n\n if (handleId === this.handleId && this.defaultDataChannelLabel === (data === null || data === void 0 ? void 0 : data.label)) {\n this._isDataChannelOpen = (data === null || data === void 0 ? void 0 : data.state) === 'open';\n this.emit('dataChannel', (data === null || data === void 0 ? void 0 : data.state) === 'open');\n }\n }\n\n if (type === 'error') {\n this.emit('error', {\n type: 'warning',\n id: 9,\n message: 'data event warning',\n data: [handleId, data]\n });\n\n if (handle) {\n let config = handle.webrtcStuff;\n\n if (this.defaultDataChannelLabel === data.label) {\n config.dataChannelOpen = false;\n }\n }\n\n if (handleId === this.handleId && this.defaultDataChannelLabel === data.label) {\n this._isDataChannelOpen = false;\n this.emit('dataChannel', false);\n }\n }\n\n if (handleId === this.handleId && type === 'message') {\n let d = null;\n\n try {\n d = JSON.parse(data);\n } catch (e) {\n this.emit('error', {\n type: 'warning',\n id: 10,\n message: 'data message parse error',\n data: [handleId, e]\n });\n return;\n }\n\n this.emit('data', d);\n }\n } //removeHandle === true -> hangup, detach, removeHandle === false -> hangup\n\n\n _removeParticipant(handleId, rfid) {\n let removeHandle = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n\n let handle = this._getHandle(handleId, rfid);\n\n if (!handle) {\n return Promise.resolve();\n } else {\n handleId = handle.handleId;\n }\n\n return this._send({\n \"janus\": \"hangup\",\n \"handle_id\": handleId\n }, true).then(() => removeHandle ? this._send({\n \"janus\": \"detach\",\n \"handle_id\": handleId\n }, true) : Promise.resolve()).finally(() => {\n try {\n if (handle.webrtcStuff.stream && !this.isRestarting) {\n handle.webrtcStuff.stream.getTracks().forEach(track => track.stop());\n }\n } catch (e) {// Do nothing\n }\n\n handle.webrtcStuff.stream = null;\n\n if (handle.webrtcStuff.dataChannel) {\n Object.keys(handle.webrtcStuff.dataChannel).forEach(label => {\n handle.webrtcStuff.dataChannel[label].onmessage = null;\n handle.webrtcStuff.dataChannel[label].onopen = null;\n handle.webrtcStuff.dataChannel[label].onclose = null;\n handle.webrtcStuff.dataChannel[label].onerror = null;\n });\n }\n\n if (handle.webrtcStuff.pc) {\n handle.webrtcStuff.pc.onicecandidate = null;\n handle.webrtcStuff.pc.ontrack = null;\n handle.webrtcStuff.pc.ondatachannel = null;\n handle.webrtcStuff.pc.onconnectionstatechange = null;\n handle.webrtcStuff.pc.oniceconnectionstatechange = null;\n }\n\n try {\n handle.webrtcStuff.pc.close();\n } catch (e) {}\n\n handle.webrtcStuff = {\n stream: null,\n mySdp: null,\n mediaConstraints: null,\n pc: null,\n dataChannelOpen: false,\n dataChannel: null,\n dtmfSender: null,\n trickle: true,\n iceDone: false\n };\n\n if (handleId === this.handleId) {\n this._isDataChannelOpen = false;\n this._isPublished = false;\n this.emit('published', {\n status: false,\n hasStream: false\n });\n this.emit('removeLocalParticipant', {\n id: handleId,\n userId: handle.userId\n });\n } else {\n this.emit(this._getRemoveParticipantEventName(handleId), {\n id: handleId,\n userId: handle.userId\n });\n }\n\n if (removeHandle) {\n let handleIndex = this._participants.findIndex(p => p.handleId === handleId);\n\n this._participants.splice(handleIndex, 1);\n }\n\n return true;\n });\n }\n\n _createParticipant() {\n let userId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let rfid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n return this._send({\n \"janus\": \"attach\",\n \"plugin\": this.pluginName\n }).then(json => {\n let handleId = json.data[\"id\"];\n let handle = {\n handleId,\n rfid,\n userId,\n webrtcStuff: {\n stream: null,\n mySdp: null,\n mediaConstraints: null,\n pc: null,\n dataChannelOpen: false,\n dataChannel: null,\n dtmfSender: null,\n trickle: true,\n iceDone: false,\n isIceRestarting: false\n }\n };\n\n this._participants.push(handle);\n\n return handle;\n });\n }\n\n _joinRoom(roomId, pin, userId, display) {\n return this.sendMessage(this.handleId, {\n body: {\n \"request\": \"join\",\n \"room\": roomId,\n \"pin\": pin,\n \"ptype\": \"publisher\",\n \"display\": display,\n ...(this.webrtcVersion > 1000 ? {\n id: userId\n } : {})\n }\n }, false, true);\n }\n\n _watchStream(id) {\n return this.sendMessage(this.handleId, {\n body: {\n \"request\": \"watch\",\n id: parseInt(id)\n }\n }, false, true);\n }\n\n _leaveRoom() {\n let dontWait = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n return this._hasJoined ? this.sendMessage(this.handleId, {\n body: {\n \"request\": \"leave\"\n }\n }, dontWait).finally(() => {\n this._hasJoined = false;\n this.emit('joined', false);\n }) : Promise.resolve();\n } // internal reconnect\n\n\n _reconnect() {\n if (this.connectingPromise) {\n return this.connectingPromise;\n }\n\n if (this.ws) {\n this._wipeListeners();\n\n if (this.ws.readyState === 1) {\n this.ws.close();\n }\n }\n\n this._stopKeepAlive();\n\n this.connectingPromise = new Promise((resolve, reject) => {\n this.emit('joining', true);\n this.ws = new WebSocket(this.server, 'janus-protocol');\n this.__connectionClosedBoundFn = this._connectionClosed.bind(this);\n this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);\n this.ws.addEventListener('close', this.__connectionClosedBoundFn);\n this.ws.addEventListener('message', this.__handleWsEventsBoundFn);\n\n this.ws.onopen = () => {\n this._send({\n \"janus\": \"claim\"\n }).then(json => {\n this.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n this._startKeepAlive();\n\n this.connectingPromise = null;\n this.emit('joining', false);\n this._retries = 0;\n resolve(json);\n }).catch(error => {\n this.connectingPromise = null;\n this.emit('joining', false);\n reject({\n type: 'error',\n id: 11,\n message: 'reconnection error',\n data: error\n });\n });\n }; // this is called before 'close' event callback so it doesn't break reconnect loop\n\n\n this.ws.onerror = e => {\n this.connectingPromise = null;\n this.emit('joining', false);\n reject({\n type: 'warning',\n id: 12,\n message: 'ws reconnection error',\n data: e\n });\n };\n });\n return this.connectingPromise;\n }\n\n connect(roomId, pin, server, iceServers, token, display, userId) {\n let webrtcVersion = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 0;\n let initialBitrate = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : 0;\n let isMonitor = arguments.length > 9 ? arguments[9] : undefined;\n let recordingFilename = arguments.length > 10 ? arguments[10] : undefined;\n\n if (this.connectingPromise) {\n return this.connectingPromise;\n }\n\n this.emit('joined', false);\n\n if (this.ws) {\n this._wipeListeners();\n }\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = null;\n this.sessionId = null;\n this.server = server;\n this.iceServers = iceServers;\n this.token = token;\n this.roomId = roomId;\n this.pin = pin;\n this.display = display;\n this.userId = userId;\n this.webrtcVersion = webrtcVersion;\n this.initialBitrate = initialBitrate;\n this.isMonitor = isMonitor;\n this.recordingFilename = recordingFilename;\n this.disconnectingPromise = null;\n this.connectingPromise = new Promise((resolve, reject) => {\n this.emit('joining', true);\n this.ws = new WebSocket(this.server, 'janus-protocol');\n this.__connectionClosedBoundFn = this._connectionClosed.bind(this);\n this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);\n this.ws.addEventListener('close', this.__connectionClosedBoundFn);\n this.ws.addEventListener('message', this.__handleWsEventsBoundFn);\n\n this.ws.onopen = () => {\n this._retries = 0;\n\n this._send({\n \"janus\": \"create\"\n }).then(json => {\n this.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n this._startKeepAlive();\n\n return 1;\n }).then(() => this._createParticipant(userId)).then(handle => {\n this.handleId = handle.handleId;\n return 1;\n }).then(() => this._joinRoom(roomId, pin, userId, display)).then(() => {\n this.connectingPromise = null;\n this.emit('joining', false);\n resolve(this);\n }).catch(error => {\n this.connectingPromise = null;\n this.emit('joining', false);\n reject({\n type: 'error',\n id: 13,\n message: 'connection error',\n data: error\n });\n });\n };\n\n this.ws.onerror = e => {\n this.connectingPromise = null;\n this.emit('joining', false);\n reject({\n type: 'error',\n id: 14,\n message: 'ws connection error',\n data: e\n });\n };\n });\n return this.connectingPromise;\n }\n\n disconnect() {\n if (this.disconnectingPromise) {\n return this.disconnectingPromise;\n }\n\n let _hasJoined = this._hasJoined;\n clearTimeout(this._messageTimeoutId);\n clearTimeout(this._dataChannelTimeoutId);\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = Promise.all(this._participants.map(p => this._removeParticipant(p.handleId))).finally(() => {\n this._wipeListeners();\n\n if (this.ws && this.ws.readyState === 1) {\n this._send({\n \"janus\": \"destroy\"\n }, true);\n\n this.ws.close();\n }\n\n this.sessionId = null; //TODO: Just in case something crashed along the way\n\n this._isPublished = false;\n this._hasJoined = false;\n this.emit('published', {\n status: false,\n hasStream: false\n });\n this.emit('joined', false);\n this.emit('disconnect', _hasJoined);\n return Promise.resolve('Disconnected');\n });\n return this.disconnectingPromise;\n }\n\n startStream(streamId, server, iceServers, token, userId) {\n if (this.connectingPromise) {\n return this.connectingPromise;\n }\n\n this.emit('streaming', false);\n\n if (this.ws) {\n this._wipeListeners();\n }\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = null;\n this.sessionId = null;\n this.server = server;\n this.iceServers = iceServers;\n this.token = token;\n this.streamId = streamId;\n this.userId = userId;\n this.connectingPromise = new Promise((resolve, reject) => {\n this.emit('streamStarting', true);\n this.ws = new WebSocket(this.server, 'janus-protocol');\n this.__connectionClosedBoundFn = this._connectionClosed.bind(this);\n this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);\n this.ws.addEventListener('close', this.__connectionClosedBoundFn);\n this.ws.addEventListener('message', this.__handleWsEventsBoundFn);\n\n this.ws.onopen = () => {\n this._retries = 0;\n\n this._send({\n \"janus\": \"create\"\n }).then(json => {\n this.sessionId = json[\"session_id\"] ? json[\"session_id\"] : json.data[\"id\"];\n\n this._startKeepAlive();\n\n return 1;\n }).then(() => this._createParticipant(userId)).then(handle => {\n this.handleId = handle.handleId;\n return 1;\n }).then(() => this._watchStream(streamId)).then(() => {\n this.connectingPromise = null;\n this.emit('streamStarting', false);\n resolve(this);\n }).catch(error => {\n this.connectingPromise = null;\n this.emit('streamStarting', false);\n reject({\n type: 'error',\n id: 13,\n message: 'connection error',\n data: error\n });\n });\n };\n\n this.ws.onerror = e => {\n this.connectingPromise = null;\n this.emit('streamStarting', false);\n reject({\n type: 'error',\n id: 14,\n message: 'ws connection error',\n data: e\n });\n };\n });\n return this.connectingPromise;\n }\n\n stopStream() {\n if (this.disconnectingPromise) {\n return this.disconnectingPromise;\n }\n\n let _isStreaming = this._isStreaming;\n\n this._stopKeepAlive();\n\n this.disconnectingPromise = this.sendMessage(this.handleId, {\n body: {\n \"request\": \"stop\"\n }\n }, false, true).then(() => this._removeParticipant(this.handleId)).finally(() => {\n this._wipeListeners();\n\n this._send({\n \"janus\": \"destroy\"\n }, true);\n\n if (this.ws && this.ws.readyState === 1) {\n this.ws.close();\n }\n\n this.sessionId = null;\n this._isStreaming = false;\n this.emit('streaming', false); // last event\n\n this.emit('disconnect', _isStreaming);\n this.disconnectingPromise = null;\n return Promise.resolve('Disconnected');\n });\n return this.disconnectingPromise;\n }\n\n destroy() {\n if (this.sessiontype === 'reactooroom') {\n return this.disconnect().then(() => {\n this.clear();\n return true;\n });\n } else if (this.sessiontype === 'streaming') {\n return this.stopStream().then(() => {\n this.clear();\n return true;\n });\n }\n }\n\n _enableDebug() {\n this._log = console.log.bind(console);\n }\n\n _getHandle(handleId) {\n let rfid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n return this._participants.find(p => p.handleId === handleId || rfid && p.rfid === rfid);\n }\n\n _getStats() {\n let type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n return Promise.all(this._participants.map(participant => {\n let mediaTrack = null;\n\n if (type === 'video') {\n mediaTrack = participant.webrtcStuff && participant.webrtcStuff.stream && participant.webrtcStuff.stream.getVideoTracks().length && participant.webrtcStuff.stream.getVideoTracks()[0];\n } else if (type === 'audio') {\n mediaTrack = participant.webrtcStuff && participant.webrtcStuff.stream && participant.webrtcStuff.stream.getAudioTracks().length && participant.webrtcStuff.stream.getAudioTracks()[0];\n }\n\n return participant.webrtcStuff && participant.webrtcStuff.pc && participant.webrtcStuff.pc.getStats(mediaTrack).then(r => ({\n handle: participant,\n stats: r\n })).catch(e => Promise.resolve({\n handle: participant,\n stats: e\n }));\n }));\n }\n\n _sendTrickleCandidate(handleId, candidate) {\n return this._send({\n \"janus\": \"trickle\",\n \"candidate\": candidate,\n \"handle_id\": handleId\n });\n }\n\n _webrtc(handleId) {\n let enableOntrack = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n this.emit('error', {\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'create rtc connection']\n });\n }\n\n let config = handle.webrtcStuff;\n\n if (!config.pc) {\n let pc_config = {\n \"iceServers\": this.iceServers,\n \"iceTransportPolicy\": 'all',\n \"bundlePolicy\": undefined\n };\n pc_config[\"sdpSemantics\"] = this.isUnifiedPlan ? \"unified-plan\" : \"plan-b\";\n let pc_constraints = {\n \"optional\": [{\n \"DtlsSrtpKeyAgreement\": true\n }]\n };\n\n if (this._ipv6Support === true) {\n pc_constraints.optional.push({\n \"googIPv6\": true\n });\n }\n\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === \"edge\") {\n // This is Edge, enable BUNDLE explicitly\n pc_config.bundlePolicy = \"max-bundle\";\n }\n\n this._log('new RTCPeerConnection', pc_config, pc_constraints);\n\n config.pc = new RTCPeerConnection(pc_config, pc_constraints);\n\n config.pc.onconnectionstatechange = () => {\n if (config.pc.connectionState === 'failed') {\n this._iceRestart(handleId);\n }\n\n this.emit('connectionState', [handleId, handleId === this.handleId, config.pc.connectionState]);\n\n if (handleId !== this.handleId && config.pc.connectionState === 'connected') {\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n stream: config.stream,\n track: null,\n optional: true,\n constructId: this.constructId,\n metaData: this.options.metaData,\n adding: false,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n }\n };\n\n config.pc.oniceconnectionstatechange = () => {\n if (config.pc.iceConnectionState === 'failed') {\n this._iceRestart(handleId);\n }\n\n this.emit('iceState', [handleId, handleId === this.handleId, config.pc.iceConnectionState]);\n\n if (handleId !== this.handleId && (config.pc.iceConnectionState === 'completed' || config.pc.iceConnectionState === 'connected')) {\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n stream: config.stream,\n track: null,\n optional: true,\n constructId: this.constructId,\n metaData: this.options.metaData,\n adding: false,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n }\n };\n\n config.pc.onicecandidate = event => {\n if (event.candidate == null || webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === 'edge' && event.candidate.candidate.indexOf('endOfCandidates') > 0) {\n config.iceDone = true;\n\n this._sendTrickleCandidate(handleId, {\n \"completed\": true\n }).catch(e => {\n this.emit('error', e);\n });\n } else {\n // JSON.stringify doesn't work on some WebRTC objects anymore\n // See https://code.google.com/p/chromium/issues/detail?id=467366\n var candidate = {\n \"candidate\": event.candidate.candidate,\n \"sdpMid\": event.candidate.sdpMid,\n \"sdpMLineIndex\": event.candidate.sdpMLineIndex\n };\n\n this._sendTrickleCandidate(handleId, candidate).catch(e => {\n this.emit('error', e);\n });\n }\n };\n\n if (enableOntrack) {\n config.pc.ontrack = event => {\n if (!event.streams) return; //config.stream = event.streams[0];\n\n if (!config.stream) {\n config.stream = new MediaStream();\n }\n\n if (event.track) {\n let mid = event.transceiver ? event.transceiver.mid : event.track.id;\n config.stream.addTrack(event.track);\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n mid,\n id: handle.handleId,\n userId: handle.userId,\n stream: config.stream,\n track: event.track,\n constructId: this.constructId,\n metaData: this.options.metaData,\n adding: true,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n if (event.track.onended) return;\n\n event.track.onended = ev => {\n let mid = ev.target.id;\n\n if (this.isUnifiedPlan) {\n let transceiver = config.pc.getTransceivers().find(t => t.receiver.track === ev.target);\n mid = transceiver.mid;\n }\n\n if (config.stream) {\n config.stream && config.stream.removeTrack(ev.target);\n this.emit(this._getAddParticipantEventName(handle.handleId), {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n mid,\n userId: handle.userId,\n stream: config.stream,\n track: ev.target,\n constructId: this.constructId,\n metaData: this.options.metaData,\n adding: false,\n removing: true,\n hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),\n hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)\n });\n }\n };\n\n event.track.onmute = ev => {\n this._log('remoteTrackMuted', 'onmute');\n\n let mid = ev.target.id;\n\n if (this.isUnifiedPlan) {\n let transceiver = config.pc.getTransceivers().find(t => t.receiver.track === ev.target);\n mid = transceiver.mid;\n }\n\n this.emit('remoteTrackMuted', {\n id: handle.handleId,\n mid,\n userId: handle.userId,\n stream: config.stream,\n kind: ev.target.kind,\n track: ev.target,\n muted: true\n });\n };\n\n event.track.onunmute = ev => {\n this._log('remoteTrackMuted', 'onunmute');\n\n let mid = ev.target.id;\n\n if (this.isUnifiedPlan) {\n let transceiver = config.pc.getTransceivers().find(t => t.receiver.track === ev.target);\n mid = transceiver.mid;\n }\n\n this.emit('remoteTrackMuted', {\n id: handle.handleId,\n mid,\n userId: handle.userId,\n stream: config.stream,\n kind: ev.target.kind,\n track: ev.target,\n muted: false\n });\n };\n }\n };\n }\n }\n\n if (!config.dataChannel || !config.dataChannelOpen) {\n config.dataChannel = {};\n\n var onDataChannelMessage = event => {\n this._handleDataEvents(handleId, 'message', event.data);\n };\n\n var onDataChannelStateChange = event => {\n let label = event.target.label;\n let protocol = event.target.protocol;\n let state = config.dataChannel[label] ? config.dataChannel[label].readyState : \"null\";\n\n this._handleDataEvents(handleId, 'state', {\n state,\n label\n });\n }; //TODO: check this\n\n\n var onDataChannelError = error => {\n var _error$channel;\n\n this._handleDataEvents(handleId, 'error', {\n label: error === null || error === void 0 ? void 0 : (_error$channel = error.channel) === null || _error$channel === void 0 ? void 0 : _error$channel.label,\n error\n });\n };\n\n const createDataChannel = (label, protocol, incoming) => {\n let options = {\n ordered: true\n };\n\n if (!incoming) {\n if (protocol) {\n options = { ...options,\n protocol\n };\n }\n\n config.dataChannel[label] = config.pc.createDataChannel(label, options);\n } else {\n config.dataChannel[label] = incoming;\n }\n\n config.dataChannel[label].onmessage = onDataChannelMessage;\n config.dataChannel[label].onopen = onDataChannelStateChange;\n config.dataChannel[label].onclose = onDataChannelStateChange;\n config.dataChannel[label].onerror = onDataChannelError;\n };\n\n createDataChannel(this.defaultDataChannelLabel, null, null);\n\n config.pc.ondatachannel = function (event) {\n createDataChannel(event.channel.label, event.channel.protocol, event.channel);\n };\n }\n }\n\n _webrtcPeer(handleId, jsep) {\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'rtc peer']\n });\n }\n\n var config = handle.webrtcStuff;\n\n if (jsep !== undefined && jsep !== null) {\n if (config.pc === null) {\n this._log(\"No PeerConnection: if this is an answer, use createAnswer and not _webrtcPeer\");\n\n return Promise.resolve(null);\n }\n\n return config.pc.setRemoteDescription(jsep).then(() => {\n config.remoteSdp = jsep.sdp; // Any trickle candidate we cached?\n\n if (config.candidates && config.candidates.length > 0) {\n for (var i = 0; i < config.candidates.length; i++) {\n var candidate = config.candidates[i];\n\n if (!candidate || candidate.completed === true) {\n config.pc.addIceCandidate(null);\n } else {\n config.pc.addIceCandidate(candidate);\n }\n }\n\n config.candidates = [];\n } // Done\n\n\n return true;\n });\n } else {\n return Promise.reject({\n type: 'warning',\n id: 22,\n message: 'rtc peer',\n data: [handleId, 'invalid jsep']\n });\n }\n }\n\n _iceRestart(handleId) {\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n return;\n }\n\n var config = handle.webrtcStuff; // Already restarting;\n\n if (config.isIceRestarting) {\n return;\n }\n\n if (this.handleId === handleId) {\n this._log('Performing local ICE restart');\n\n config.isIceRestarting = true;\n let hasAudio = !!(config.stream && config.stream.getAudioTracks().length > 0);\n let hasVideo = !!(config.stream && config.stream.getVideoTracks().length > 0);\n\n this._createAO('offer', handleId, true, [hasAudio, false, hasVideo, false]).then(jsep => {\n if (!jsep) {\n return null;\n }\n\n return this.sendMessage(handleId, {\n body: {\n \"request\": \"configure\",\n \"audio\": hasAudio,\n \"video\": hasVideo,\n \"data\": true,\n ...(this.recordingFilename ? {\n filename: this.recordingFilename\n } : {})\n },\n jsep\n });\n }).then(r => {\n config.isIceRestarting = false;\n\n this._log('ICE restart success');\n }).catch(e => {\n config.isIceRestarting = false;\n this.emit('warning', {\n type: 'error',\n id: 28,\n message: 'iceRestart failed',\n data: e\n });\n });\n } else {\n this._log('Performing remote ICE restart', handleId);\n\n config.isIceRestarting = true;\n return this.sendMessage(handleId, {\n body: {\n \"request\": \"configure\",\n \"restart\": true\n }\n }).then(() => {\n config.isIceRestarting = false;\n }).catch(() => {\n config.isIceRestarting = false;\n });\n }\n }\n\n _createAO() {\n let type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'offer';\n let handleId = arguments.length > 1 ? arguments[1] : undefined;\n let iceRestart = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n let [audioSend, audioRecv, videoSend, videoRecv] = arguments.length > 3 ? arguments[3] : undefined;\n\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'createAO', type]\n });\n }\n\n let methodName = null;\n\n if (type === 'offer') {\n methodName = 'createOffer';\n } else {\n methodName = 'createAnswer';\n }\n\n var config = handle.webrtcStuff; // https://code.google.com/p/webrtc/issues/detail?id=3508\n\n var mediaConstraints = {};\n\n if (this.isUnifiedPlan) {\n var audioTransceiver = null,\n videoTransceiver = null;\n var transceivers = config.pc.getTransceivers();\n\n if (transceivers && transceivers.length > 0) {\n for (var i in transceivers) {\n var t = transceivers[i];\n\n if (t.sender && t.sender.track && t.sender.track.kind === \"audio\" && t.stopped === false || t.receiver && t.receiver.track && t.receiver.track.kind === \"audio\" && t.stopped === false) {\n if (!audioTransceiver) audioTransceiver = t;\n continue;\n }\n\n if (t.sender && t.sender.track && t.sender.track.kind === \"video\" && t.stopped === false || t.receiver && t.receiver.track && t.receiver.track.kind === \"video\" && t.stopped === false) {\n if (!videoTransceiver) videoTransceiver = t;\n continue;\n }\n }\n } // Handle audio (and related changes, if any)\n\n\n if (!audioSend && !audioRecv) {\n // Audio disabled: have we removed it?\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"inactive\");\n } else {\n audioTransceiver.direction = \"inactive\";\n }\n }\n } else {\n // Take care of audio m-line\n if (audioSend && audioRecv) {\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"sendrecv\");\n } else {\n audioTransceiver.direction = \"sendrecv\";\n }\n }\n } else if (audioSend && !audioRecv) {\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"sendonly\");\n } else {\n audioTransceiver.direction = \"sendonly\";\n }\n }\n } else if (!audioSend && audioRecv) {\n if (audioTransceiver) {\n if (audioTransceiver.setDirection) {\n audioTransceiver.setDirection(\"recvonly\");\n } else {\n audioTransceiver.direction = \"recvonly\";\n }\n } else {\n // In theory, this is the only case where we might not have a transceiver yet\n audioTransceiver = config.pc.addTransceiver(\"audio\", {\n direction: \"recvonly\"\n });\n }\n }\n } // Handle video (and related changes, if any)\n\n\n if (!videoSend && !videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"inactive\");\n } else {\n videoTransceiver.direction = \"inactive\";\n }\n }\n } else {\n // Take care of video m-line\n if (videoSend && videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"sendrecv\");\n } else {\n videoTransceiver.direction = \"sendrecv\";\n }\n }\n } else if (videoSend && !videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"sendonly\");\n } else {\n videoTransceiver.direction = \"sendonly\";\n }\n }\n } else if (!videoSend && videoRecv) {\n if (videoTransceiver) {\n if (videoTransceiver.setDirection) {\n videoTransceiver.setDirection(\"recvonly\");\n } else {\n videoTransceiver.direction = \"recvonly\";\n }\n } else {\n // In theory, this is the only case where we might not have a transceiver yet\n videoTransceiver = config.pc.addTransceiver(\"video\", {\n direction: \"recvonly\"\n });\n }\n }\n }\n } else {\n if (webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === \"firefox\" || webrtc_adapter__WEBPACK_IMPORTED_MODULE_0__[\"default\"].browserDetails.browser === \"edge\") {\n mediaConstraints = {\n offerToReceiveAudio: audioRecv,\n offerToReceiveVideo: videoRecv\n };\n } else {\n mediaConstraints = {\n mandatory: {\n OfferToReceiveAudio: audioRecv,\n OfferToReceiveVideo: videoRecv\n }\n };\n }\n }\n\n if (iceRestart) {\n mediaConstraints[\"iceRestart\"] = true;\n }\n\n return config.pc[methodName](mediaConstraints).then(function (response) {\n config.mySdp = response.sdp;\n\n let _p = config.pc.setLocalDescription(response).catch(e => {\n return Promise.reject({\n type: 'warning',\n id: 24,\n message: 'setLocalDescription',\n data: [handleId, e]\n });\n });\n\n config.mediaConstraints = mediaConstraints;\n\n if (!config.iceDone && !config.trickle) {\n // Don't do anything until we have all candidates\n return Promise.resolve(null);\n } // JSON.stringify doesn't work on some WebRTC objects anymore\n // See https://code.google.com/p/chromium/issues/detail?id=467366\n\n\n var jsep = {\n \"type\": response.type,\n \"sdp\": response.sdp\n };\n return _p.then(() => jsep);\n }, e => {\n return Promise.reject({\n type: 'warning',\n id: 25,\n message: methodName,\n data: [handleId, e]\n });\n });\n }\n\n _publishRemote(handleId, jsep) {\n let handle = this._getHandle(handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'warning',\n id: 15,\n message: 'id non-existent',\n data: [handleId, 'publish remote participant']\n });\n }\n\n this._webrtc(handleId, true);\n\n let config = handle.webrtcStuff;\n\n if (jsep) {\n return config.pc.setRemoteDescription(jsep).then(() => {\n config.remoteSdp = jsep.sdp; // Any trickle candidate we cached?\n\n if (config.candidates && config.candidates.length > 0) {\n for (var i = 0; i < config.candidates.length; i++) {\n var candidate = config.candidates[i];\n\n if (!candidate || candidate.completed === true) {\n // end-of-candidates\n config.pc.addIceCandidate(null);\n } else {\n // New candidate\n config.pc.addIceCandidate(candidate);\n }\n }\n\n config.candidates = [];\n } // Create the answer now\n\n\n return this._createAO('answer', handleId, false, [false, true, false, true]).then(_jsep => {\n if (!_jsep) {\n this.emit('error', {\n type: 'warning',\n id: 19,\n message: 'publish remote participant',\n data: [handleId, 'no jsep']\n });\n return Promise.resolve();\n }\n\n return this.sendMessage(handleId, {\n \"body\": {\n \"request\": \"start\",\n ...(this.roomId && {\n \"room\": this.roomId\n }),\n ...(this.pin && {\n pin: this.pin\n })\n },\n \"jsep\": _jsep\n });\n });\n }, e => Promise.reject({\n type: 'warning',\n id: 23,\n message: 'setRemoteDescription',\n data: [handleId, e]\n }));\n } else {\n return Promise.resolve();\n }\n } //Public methods\n\n\n publishLocal(stream) {\n let {\n keepAudio = false,\n keepVideo = false\n } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n this.emit('publishing', true);\n\n let handle = this._getHandle(this.handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'error',\n id: 21,\n message: 'no local id, connect before publishing',\n data: null\n });\n }\n\n this._webrtc(this.handleId);\n\n let config = handle.webrtcStuff;\n\n if (stream) {\n if (!config.stream) {\n config.stream = stream;\n stream.getTracks().forEach(function (track) {\n config.pc.addTrack(track, stream);\n });\n } else {\n /* UPDATE Audio */\n let replaceAudio = stream.getAudioTracks().length;\n\n if (replaceAudio || !keepAudio) {\n //this will stop existing tracks\n let oldAudioStream = config.stream.getAudioTracks()[0];\n\n if (oldAudioStream) {\n config.stream.removeTrack(oldAudioStream);\n\n try {\n oldAudioStream.stop();\n } catch (e) {\n this._log(e);\n }\n }\n }\n\n if (config.pc.getSenders() && config.pc.getSenders().length) {\n if (replaceAudio && this.isUnifiedPlan) {//using replace\n } else {\n for (let index in config.pc.getSenders()) {\n let s = config.pc.getSenders()[index];\n\n if (s && s.track && s.track.kind === \"audio\") {\n config.pc.removeTrack(s);\n }\n }\n }\n }\n\n if (replaceAudio) {\n config.stream.addTrack(stream.getAudioTracks()[0]);\n var audioTransceiver = null;\n\n if (this.isUnifiedPlan) {\n let transceivers = config.pc.getTransceivers();\n\n if (transceivers && transceivers.length > 0) {\n for (let i in transceivers) {\n let t = transceivers[i];\n\n if (t.sender && t.sender.track && t.sender.track.kind === \"audio\" && t.stopped === false || t.receiver && t.receiver.track && t.receiver.track.kind === \"audio\" && t.stopped === false) {\n audioTransceiver = t;\n break;\n }\n }\n }\n }\n\n if (audioTransceiver && audioTransceiver.sender) {\n audioTransceiver.sender.replaceTrack(stream.getAudioTracks()[0]);\n } else {\n config.pc.addTrack(stream.getAudioTracks()[0], stream);\n }\n }\n /* UPDATE Video */\n\n\n let replaceVideo = stream.getVideoTracks().length;\n\n if (replaceVideo || !keepVideo) {\n let oldVideoStream = config.stream.getVideoTracks()[0];\n\n if (oldVideoStream) {\n config.stream.removeTrack(oldVideoStream);\n\n try {\n oldVideoStream.stop();\n } catch (e) {\n this._log(e);\n }\n }\n }\n\n if (config.pc.getSenders() && config.pc.getSenders().length) {\n if (replaceVideo && this.isUnifiedPlan) {//using replace\n } else {\n for (let index in config.pc.getSenders()) {\n let s = config.pc.getSenders()[index];\n\n if (s && s.track && s.track.kind === \"video\") {\n config.pc.removeTrack(s);\n }\n }\n }\n }\n\n if (replaceVideo) {\n config.stream.addTrack(stream.getVideoTracks()[0]);\n var videoTransceiver = null;\n\n if (this.isUnifiedPlan) {\n let transceivers = config.pc.getTransceivers();\n\n if (transceivers && transceivers.length > 0) {\n for (let i in transceivers) {\n let t = transceivers[i];\n\n if (t.sender && t.sender.track && t.sender.track.kind === \"video\" && t.stopped === false || t.receiver && t.receiver.track && t.receiver.track.kind === \"video\" && t.stopped === false) {\n videoTransceiver = t;\n break;\n }\n }\n }\n }\n\n if (videoTransceiver && videoTransceiver.sender) {\n //TODO: check if t.stopped === false still gets us videoTransceiver\n videoTransceiver.sender.replaceTrack(stream.getVideoTracks()[0]);\n } else {\n config.pc.addTrack(stream.getVideoTracks()[0], stream);\n }\n }\n }\n }\n\n let hasAudio = !!(stream && stream.getAudioTracks().length > 0);\n let hasVideo = !!(stream && stream.getVideoTracks().length > 0);\n let isAudioMuted = !stream || stream.getAudioTracks().length === 0 || !stream.getAudioTracks()[0].enabled;\n let isVideoMuted = !stream || stream.getVideoTracks().length === 0 || !stream.getVideoTracks()[0].enabled;\n this.isAudioEnabed = hasAudio;\n this.isVideoEnabled = hasVideo;\n this.isAudioMuted = isAudioMuted;\n this.isVideoMuted = isVideoMuted;\n return this._createAO('offer', this.handleId, false, [hasAudio, false, hasVideo, false]).then(jsep => {\n if (!jsep) {\n return null;\n } //HOTFIX: Temporary fix for Safari 13\n\n\n if (jsep.sdp && jsep.sdp.indexOf(\"\\r\\na=ice-ufrag\") === -1) {\n jsep.sdp = jsep.sdp.replace(\"\\na=ice-ufrag\", \"\\r\\na=ice-ufrag\");\n }\n\n return this.sendMessage(this.handleId, {\n body: {\n \"request\": \"configure\",\n \"audio\": hasAudio,\n \"video\": hasVideo,\n \"data\": true,\n ...(this.recordingFilename ? {\n filename: this.recordingFilename\n } : {})\n },\n jsep\n });\n }).then(r => {\n if (this._isDataChannelOpen) {\n return Promise.resolve(r);\n } else {\n return new Promise((resolve, reject) => {\n let __ = val => {\n if (val) {\n clearTimeout(this._dataChannelTimeoutId);\n this.off('dataChannel', __, this);\n resolve(this);\n }\n };\n\n this._dataChannelTimeoutId = setTimeout(() => {\n this.off('dataChannel', __, this);\n reject({\n type: 'error',\n id: 27,\n message: 'Data channel did not open',\n data: null\n });\n }, 5000);\n this.on('dataChannel', __, this);\n });\n }\n }).then(r => {\n this._isPublished = true;\n\n if (config.stream) {\n let tracks = config.stream.getTracks();\n tracks.forEach(track => {\n // used as a flag to not emit tracks that been already emitted\n if (!track.onended) {\n this.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n track,\n stream: config.stream,\n adding: true,\n constructId: this.constructId,\n metaData: this.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n\n track.onended = ev => {\n this.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n track: ev.target,\n stream: config.stream,\n adding: false,\n removing: true,\n constructId: this.constructId,\n metaData: this.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n };\n }\n });\n } else {\n this.emit('addLocalParticipant', {\n tid: Object(_wt_utils__WEBPACK_IMPORTED_MODULE_2__[\"generateUUID\"])(),\n id: handle.handleId,\n userId: handle.userId,\n stream: null,\n adding: false,\n constructId: this.constructId,\n metaData: this.options.metaData,\n hasAudioTrack: hasAudio,\n hasVideoTrack: hasVideo\n });\n }\n\n this.emit('published', {\n status: true,\n hasStream: !!config.stream\n });\n this.emit('publishing', false);\n this.emit('localHasVideo', hasVideo);\n this.emit('localHasAudio', hasAudio);\n this.emit('localMuted', {\n type: 'video',\n value: isVideoMuted\n });\n this.emit('localMuted', {\n type: 'audio',\n value: isAudioMuted\n });\n return r;\n }).catch(e => {\n this.emit('publishing', false);\n return Promise.reject(e);\n });\n }\n\n unpublishLocal() {\n let dontWait = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n return this._isPublished ? this.sendMessage(this.handleId, {\n body: {\n \"request\": \"unpublish\"\n }\n }, dontWait).finally(r => {\n this._isPublished = false;\n this.emit('published', {\n status: false,\n hasStream: false\n });\n return r;\n }) : Promise.resolve();\n }\n\n toggleAudio() {\n let value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let mid = arguments.length > 1 ? arguments[1] : undefined;\n\n let handle = this._getHandle(this.handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'error',\n id: 21,\n message: 'no local id, connect first',\n data: null\n });\n }\n\n let config = handle.webrtcStuff;\n\n if (this.isUnifiedPlan) {\n let transceiver = config.pc.getTransceivers().find(t => t.sender && t.sender.track && t.receiver.track.kind === \"audio\" && t.stopped === false && (mid ? t.mid === mid : true));\n\n if (transceiver) {\n transceiver.sender.track.enabled = value !== null ? !!value : !transceiver.sender.track.enabled;\n }\n\n this.isAudioMuted = !transceiver || !transceiver.sender.track.enabled;\n } else {\n if (config.stream && config.stream.getAudioTracks().length) {\n config.stream.getAudioTracks()[0].enabled = value !== null ? !!value : !config.stream.getAudioTracks()[0].enabled;\n }\n\n this.isAudioMuted = config.stream.getAudioTracks().length === 0 || !config.stream.getAudioTracks()[0].enabled;\n }\n\n this.emit('localMuted', {\n type: 'audio',\n value: this.isAudioMuted,\n mid\n });\n }\n\n toggleVideo() {\n let value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let mid = arguments.length > 1 ? arguments[1] : undefined;\n\n let handle = this._getHandle(this.handleId);\n\n if (!handle) {\n return Promise.reject({\n type: 'error',\n id: 21,\n message: 'no local id, connect first',\n data: null\n });\n }\n\n let config = handle.webrtcStuff;\n\n if (this.isUnifiedPlan) {\n let transceiver = config.pc.getTransceivers().find(t => t.sender && t.sender.track && t.receiver.track.kind === \"video\" && t.stopped === false && (mid ? t.mid === mid : true));\n\n if (transceiver) {\n transceiver.sender.track.enabled = value !== null ? !!value : !transceiver.sender.track.enabled;\n }\n\n this.isVideoMuted = !transceiver || !transceiver.sender.track.enabled;\n } else {\n if (config.stream && config.stream.getVideoTracks().length) {\n config.stream.getVideoTracks()[0].enabled = value !== null ? !!value : !config.stream.getVideoTracks()[0].enabled;\n }\n\n this.isVideoMuted = config.stream.getVideoTracks().length === 0 || !config.stream.getVideoTracks()[0].enabled;\n }\n\n this.emit('localMuted', {\n type: 'video',\n value: this.isVideoMuted,\n mid\n });\n }\n\n setInstructorId() {\n let instructorId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n this._instuctorId = instructorId;\n this.emit('instructorId', this._instuctorId);\n return this._instuctorId;\n }\n\n setObserverIds() {\n let observerIds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n this._observerIds = observerIds;\n this.emit('observerIds', this._observerIds);\n return this._observerIds;\n }\n\n setTalkbackIds() {\n let talkbackIds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n this._talkbackIds = talkbackIds;\n this.emit('talkbackIds', this._talkbackIds);\n return this._talkbackIds;\n }\n\n}\n\n_defineProperty(RoomSession, \"sessionTypes\", {\n 'reactooroom': 'janus.plugin.reactooroom',\n 'streaming': 'janus.plugin.streaming'\n});\n\n_defineProperty(RoomSession, \"subscriptionRules\", {\n participant: {\n watchTogether: ['participant', 'talkback'],\n videoWall: ['instructor', 'observer', 'talkback']\n },\n monitor: {\n watchTogether: ['participant'],\n videoWall: ['instructor', 'participant']\n },\n talkback: {\n watchTogether: ['participant'],\n videoWall: ['instructor', 'participant']\n },\n observer: {\n watchTogether: ['participant'],\n videoWall: ['participant']\n },\n instructor: {\n watchTogether: [],\n videoWall: []\n }\n});\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Room);\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-room.js?");
9385
9396
 
9386
9397
  /***/ }),
9387
9398
 
@@ -9393,7 +9404,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var webr
9393
9404
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
9394
9405
 
9395
9406
  "use strict";
9396
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"wait\", function() { return wait; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"getBrowserFingerprint\", function() { return getBrowserFingerprint; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"generateUUID\", function() { return generateUUID; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"setExactTimeout\", function() { return setExactTimeout; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"clearExactTimeout\", function() { return clearExactTimeout; });\n/* harmony import */ var _fingerprintjs_fingerprintjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @fingerprintjs/fingerprintjs */ \"./node_modules/@fingerprintjs/fingerprintjs/dist/fp.esm.js\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n\n\nvar wait = function wait(ms) {\n return new Promise(function (resolve) {\n return setTimeout(resolve, ms);\n });\n};\n\nvar fingerprint = _fingerprintjs_fingerprintjs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].load({\n monitoring: false\n});\n\nvar getBrowserFingerprint = function getBrowserFingerprint() {\n var instanceType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';\n var salt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';\n return fingerprint.then(function (fp) {\n return fp.get();\n }).then(function (result) {\n var components = _objectSpread(_objectSpread({}, result.components), {}, {\n instanceType: {\n value: instanceType + '_' + salt\n }\n });\n\n return [8, 13, 18, 23].reduce(function (acc, cur) {\n return acc.slice(0, cur) + '-' + acc.slice(cur);\n }, _fingerprintjs_fingerprintjs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].hashComponents(components)).substring(0, 36);\n });\n};\n\nvar generateUUID = function generateUUID() {\n var d = Date.now();\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n var r = (d + Math.random() * 16) % 16 | 0;\n d = Math.floor(d / 16);\n return (c == 'x' ? r : r & 0x3 | 0x8).toString(16);\n });\n};\n\nvar setExactTimeout = function setExactTimeout(callback, duration, resolution) {\n var start = new Date().getTime();\n var timeout = setInterval(function () {\n if (new Date().getTime() - start > duration) {\n callback();\n clearInterval(timeout);\n }\n }, resolution);\n return timeout;\n};\n\nvar clearExactTimeout = function clearExactTimeout(timeout) {\n clearInterval(timeout);\n};\n\n\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-utils.js?");
9407
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"wait\", function() { return wait; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"getBrowserFingerprint\", function() { return getBrowserFingerprint; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"generateUUID\", function() { return generateUUID; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"setExactTimeout\", function() { return setExactTimeout; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"clearExactTimeout\", function() { return clearExactTimeout; });\n/* harmony import */ var _fingerprintjs_fingerprintjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @fingerprintjs/fingerprintjs */ \"./node_modules/@fingerprintjs/fingerprintjs/dist/fp.esm.js\");\n\n\nlet wait = function (ms) {\n return new Promise(resolve => setTimeout(resolve, ms));\n};\n\nlet fingerprint = _fingerprintjs_fingerprintjs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].load({\n monitoring: false\n});\n\nlet getBrowserFingerprint = function () {\n let instanceType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';\n let salt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';\n return fingerprint.then(fp => fp.get()).then(result => {\n const components = { ...result.components,\n instanceType: {\n value: instanceType + '_' + salt\n }\n };\n return [8, 13, 18, 23].reduce((acc, cur) => {\n return acc.slice(0, cur) + '-' + acc.slice(cur);\n }, _fingerprintjs_fingerprintjs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].hashComponents(components)).substring(0, 36);\n });\n};\n\nlet generateUUID = function () {\n var d = Date.now();\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n var r = (d + Math.random() * 16) % 16 | 0;\n d = Math.floor(d / 16);\n return (c == 'x' ? r : r & 0x3 | 0x8).toString(16);\n });\n};\n\nconst setExactTimeout = function (callback, duration, resolution) {\n const start = new Date().getTime();\n const timeout = setInterval(function () {\n if (new Date().getTime() - start > duration) {\n callback();\n clearInterval(timeout);\n }\n }, resolution);\n return timeout;\n};\n\nconst clearExactTimeout = function (timeout) {\n clearInterval(timeout);\n};\n\n\n\n//# sourceURL=webpack://WatchTogetherSDK/./src/modules/wt-utils.js?");
9397
9408
 
9398
9409
  /***/ }),
9399
9410