diff --git a/dist/networked-aframe.js b/dist/networked-aframe.js index 30e5b3b3..663dd159 100644 --- a/dist/networked-aframe.js +++ b/dist/networked-aframe.js @@ -47,7 +47,7 @@ eval("// Patched version of fast-deep-equal which does not\n// allocate memory v \*************************/ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { -eval("var options = __webpack_require__(/*! ./options */ \"./src/options.js\");\n\nvar utils = __webpack_require__(/*! ./utils */ \"./src/utils.js\");\n\nvar NafLogger = __webpack_require__(/*! ./NafLogger */ \"./src/NafLogger.js\");\n\nvar Schemas = __webpack_require__(/*! ./Schemas */ \"./src/Schemas.js\");\n\nvar NetworkEntities = __webpack_require__(/*! ./NetworkEntities */ \"./src/NetworkEntities.js\");\n\nvar NetworkConnection = __webpack_require__(/*! ./NetworkConnection */ \"./src/NetworkConnection.js\");\n\nvar AdapterFactory = __webpack_require__(/*! ./adapters/AdapterFactory */ \"./src/adapters/AdapterFactory.js\");\n\nvar naf = {};\nnaf.app = '';\nnaf.room = '';\nnaf.clientId = '';\nnaf.options = options;\nnaf.utils = utils;\nnaf.log = new NafLogger();\nnaf.schemas = new Schemas();\nnaf.version = \"0.9.0\";\nnaf.adapters = new AdapterFactory();\nvar entities = new NetworkEntities();\nvar connection = new NetworkConnection(entities);\nnaf.connection = connection;\nnaf.entities = entities;\nmodule.exports = window.NAF = naf;\n\n//# sourceURL=webpack://networked-aframe/./src/NafIndex.js?"); +eval("var options = __webpack_require__(/*! ./options */ \"./src/options.js\");\n\nvar utils = __webpack_require__(/*! ./utils */ \"./src/utils.js\");\n\nvar NafLogger = __webpack_require__(/*! ./NafLogger */ \"./src/NafLogger.js\");\n\nvar Schemas = __webpack_require__(/*! ./Schemas */ \"./src/Schemas.js\");\n\nvar NetworkEntities = __webpack_require__(/*! ./NetworkEntities */ \"./src/NetworkEntities.js\");\n\nvar NetworkConnection = __webpack_require__(/*! ./NetworkConnection */ \"./src/NetworkConnection.js\");\n\nvar AdapterFactory = __webpack_require__(/*! ./adapters/AdapterFactory */ \"./src/adapters/AdapterFactory.js\");\n\nvar naf = {};\nnaf.app = '';\nnaf.room = '';\nnaf.clientId = '';\nnaf.options = options;\nnaf.utils = utils;\nnaf.log = new NafLogger();\nnaf.schemas = new Schemas();\nnaf.version = \"0.9.1\";\nnaf.adapters = new AdapterFactory();\nvar entities = new NetworkEntities();\nvar connection = new NetworkConnection(entities);\nnaf.connection = connection;\nnaf.entities = entities;\nmodule.exports = window.NAF = naf;\n\n//# sourceURL=webpack://networked-aframe/./src/NafIndex.js?"); /***/ }), @@ -117,7 +117,7 @@ eval("function _classCallCheck(instance, Constructor) { if (!(instance instanceo \****************************************/ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { -eval("function _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 _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 _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\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, \"prototype\", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } else if (call !== void 0) { throw new TypeError(\"Derived constructors may only return object or undefined\"); } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n/* global NAF */\nvar NoOpAdapter = __webpack_require__(/*! ./NoOpAdapter */ \"./src/adapters/NoOpAdapter.js\");\n\nvar EasyRtcAdapter = /*#__PURE__*/function (_NoOpAdapter) {\n _inherits(EasyRtcAdapter, _NoOpAdapter);\n\n var _super = _createSuper(EasyRtcAdapter);\n\n function EasyRtcAdapter(easyrtc) {\n var _this;\n\n _classCallCheck(this, EasyRtcAdapter);\n\n _this = _super.call(this);\n _this.easyrtc = easyrtc || window.easyrtc;\n _this.app = \"default\";\n _this.room = \"default\";\n _this.mediaStreams = {};\n _this.remoteClients = {};\n _this.pendingMediaRequests = new Map();\n _this.serverTimeRequests = 0;\n _this.timeOffsets = [];\n _this.avgTimeOffset = 0;\n\n _this.easyrtc.setPeerOpenListener(function (clientId) {\n var clientConnection = _this.easyrtc.getPeerConnectionByUserId(clientId);\n\n _this.remoteClients[clientId] = clientConnection;\n });\n\n _this.easyrtc.setPeerClosedListener(function (clientId) {\n delete _this.remoteClients[clientId];\n });\n\n return _this;\n }\n\n _createClass(EasyRtcAdapter, [{\n key: \"setServerUrl\",\n value: function setServerUrl(url) {\n this.easyrtc.setSocketUrl(url);\n }\n }, {\n key: \"setApp\",\n value: function setApp(appName) {\n this.app = appName;\n }\n }, {\n key: \"setRoom\",\n value: function setRoom(roomName) {\n this.room = roomName;\n this.easyrtc.joinRoom(roomName, null);\n } // options: { datachannel: bool, audio: bool, video: bool }\n\n }, {\n key: \"setWebRtcOptions\",\n value: function setWebRtcOptions(options) {\n // this.easyrtc.enableDebug(true);\n this.easyrtc.enableDataChannels(options.datachannel);\n this.easyrtc.enableVideo(options.video);\n this.easyrtc.enableAudio(options.audio); // TODO receive(audio|video) options ?\n\n this.easyrtc.enableVideoReceive(true);\n this.easyrtc.enableAudioReceive(true);\n }\n }, {\n key: \"setServerConnectListeners\",\n value: function setServerConnectListeners(successListener, failureListener) {\n this.connectSuccess = successListener;\n this.connectFailure = failureListener;\n }\n }, {\n key: \"setRoomOccupantListener\",\n value: function setRoomOccupantListener(occupantListener) {\n this.easyrtc.setRoomOccupantListener(function (roomName, occupants, primary) {\n occupantListener(occupants);\n });\n }\n }, {\n key: \"setDataChannelListeners\",\n value: function setDataChannelListeners(openListener, closedListener, messageListener) {\n this.easyrtc.setDataChannelOpenListener(openListener);\n this.easyrtc.setDataChannelCloseListener(closedListener);\n this.easyrtc.setPeerListener(messageListener);\n }\n }, {\n key: \"updateTimeOffset\",\n value: function updateTimeOffset() {\n var _this2 = this;\n\n var clientSentTime = Date.now() + this.avgTimeOffset;\n return fetch(document.location.href, {\n method: \"HEAD\",\n cache: \"no-cache\"\n }).then(function (res) {\n var precision = 1000;\n var serverReceivedTime = new Date(res.headers.get(\"Date\")).getTime() + precision / 2;\n var clientReceivedTime = Date.now();\n var serverTime = serverReceivedTime + (clientReceivedTime - clientSentTime) / 2;\n var timeOffset = serverTime - clientReceivedTime;\n _this2.serverTimeRequests++;\n\n if (_this2.serverTimeRequests <= 10) {\n _this2.timeOffsets.push(timeOffset);\n } else {\n _this2.timeOffsets[_this2.serverTimeRequests % 10] = timeOffset;\n }\n\n _this2.avgTimeOffset = _this2.timeOffsets.reduce(function (acc, offset) {\n return acc += offset;\n }, 0) / _this2.timeOffsets.length;\n\n if (_this2.serverTimeRequests > 10) {\n setTimeout(function () {\n return _this2.updateTimeOffset();\n }, 5 * 60 * 1000); // Sync clock every 5 minutes.\n } else {\n _this2.updateTimeOffset();\n }\n });\n }\n }, {\n key: \"connect\",\n value: function connect() {\n var _this3 = this;\n\n Promise.all([this.updateTimeOffset(), new Promise(function (resolve, reject) {\n _this3._connect(resolve, reject);\n })]).then(function (_ref) {\n var _ref2 = _slicedToArray(_ref, 2),\n _ = _ref2[0],\n clientId = _ref2[1];\n\n _this3._myRoomJoinTime = _this3._getRoomJoinTime(clientId);\n\n _this3.connectSuccess(clientId);\n })[\"catch\"](this.connectFailure);\n }\n }, {\n key: \"shouldStartConnectionTo\",\n value: function shouldStartConnectionTo(client) {\n return this._myRoomJoinTime <= client.roomJoinTime;\n }\n }, {\n key: \"startStreamConnection\",\n value: function startStreamConnection(clientId) {\n this.easyrtc.call(clientId, function (caller, media) {\n if (media === \"datachannel\") {\n NAF.log.write(\"Successfully started datachannel to \", caller);\n }\n }, function (errorCode, errorText) {\n NAF.log.error(errorCode, errorText);\n }, function (wasAccepted) {// console.log(\"was accepted=\" + wasAccepted);\n });\n }\n }, {\n key: \"closeStreamConnection\",\n value: function closeStreamConnection(clientId) {\n this.easyrtc.hangup(clientId);\n }\n }, {\n key: \"sendData\",\n value: function sendData(clientId, dataType, data) {\n // send via webrtc otherwise fallback to websockets\n this.easyrtc.sendData(clientId, dataType, data);\n }\n }, {\n key: \"sendDataGuaranteed\",\n value: function sendDataGuaranteed(clientId, dataType, data) {\n this.easyrtc.sendDataWS(clientId, dataType, data);\n }\n }, {\n key: \"broadcastData\",\n value: function broadcastData(dataType, data) {\n var roomOccupants = this.easyrtc.getRoomOccupantsAsMap(this.room); // Iterate over the keys of the easyrtc room occupants map.\n // getRoomOccupantsAsArray uses Object.keys which allocates memory.\n\n for (var roomOccupant in roomOccupants) {\n if (roomOccupants[roomOccupant] && roomOccupant !== this.easyrtc.myEasyrtcid) {\n // send via webrtc otherwise fallback to websockets\n this.easyrtc.sendData(roomOccupant, dataType, data);\n }\n }\n }\n }, {\n key: \"broadcastDataGuaranteed\",\n value: function broadcastDataGuaranteed(dataType, data) {\n var destination = {\n targetRoom: this.room\n };\n this.easyrtc.sendDataWS(destination, dataType, data);\n }\n }, {\n key: \"getConnectStatus\",\n value: function getConnectStatus(clientId) {\n var status = this.easyrtc.getConnectStatus(clientId);\n\n if (status == this.easyrtc.IS_CONNECTED) {\n return NAF.adapters.IS_CONNECTED;\n } else if (status == this.easyrtc.NOT_CONNECTED) {\n return NAF.adapters.NOT_CONNECTED;\n } else {\n return NAF.adapters.CONNECTING;\n }\n }\n }, {\n key: \"getMediaStream\",\n value: function getMediaStream(clientId) {\n var streamName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : \"audio\";\n\n if (this.mediaStreams[clientId] && this.mediaStreams[clientId][streamName]) {\n NAF.log.write(\"Already had \".concat(streamName, \" for \").concat(clientId));\n return Promise.resolve(this.mediaStreams[clientId][streamName]);\n } else {\n NAF.log.write(\"Waiting on \".concat(streamName, \" for \").concat(clientId)); // Create initial pendingMediaRequests with audio|video alias\n\n if (!this.pendingMediaRequests.has(clientId)) {\n var _pendingMediaRequests = {};\n var audioPromise = new Promise(function (resolve, reject) {\n _pendingMediaRequests.audio = {\n resolve: resolve,\n reject: reject\n };\n })[\"catch\"](function (e) {\n return NAF.log.warn(\"\".concat(clientId, \" getMediaStream Audio Error\"), e);\n });\n _pendingMediaRequests.audio.promise = audioPromise;\n var videoPromise = new Promise(function (resolve, reject) {\n _pendingMediaRequests.video = {\n resolve: resolve,\n reject: reject\n };\n })[\"catch\"](function (e) {\n return NAF.log.warn(\"\".concat(clientId, \" getMediaStream Video Error\"), e);\n });\n _pendingMediaRequests.video.promise = videoPromise;\n this.pendingMediaRequests.set(clientId, _pendingMediaRequests);\n }\n\n var pendingMediaRequests = this.pendingMediaRequests.get(clientId); // Create initial pendingMediaRequests with streamName\n\n if (!pendingMediaRequests[streamName]) {\n var streamPromise = new Promise(function (resolve, reject) {\n pendingMediaRequests[streamName] = {\n resolve: resolve,\n reject: reject\n };\n })[\"catch\"](function (e) {\n return NAF.log.warn(\"\".concat(clientId, \" getMediaStream \\\"\").concat(streamName, \"\\\" Error\"), e);\n });\n pendingMediaRequests[streamName].promise = streamPromise;\n }\n\n return this.pendingMediaRequests.get(clientId)[streamName].promise;\n }\n }\n }, {\n key: \"setMediaStream\",\n value: function setMediaStream(clientId, stream, streamName) {\n var pendingMediaRequests = this.pendingMediaRequests.get(clientId); // return undefined if there is no entry in the Map\n\n var clientMediaStreams = this.mediaStreams[clientId] = this.mediaStreams[clientId] || {};\n\n if (streamName === 'default') {\n // Safari doesn't like it when you use a mixed media stream where one of the tracks is inactive, so we\n // split the tracks into two streams.\n // Add mediaStreams audio streamName alias\n var audioTracks = stream.getAudioTracks();\n\n if (audioTracks.length > 0) {\n var audioStream = new MediaStream();\n\n try {\n audioTracks.forEach(function (track) {\n return audioStream.addTrack(track);\n });\n clientMediaStreams.audio = audioStream;\n } catch (e) {\n NAF.log.warn(\"\".concat(clientId, \" setMediaStream \\\"audio\\\" alias Error\"), e);\n } // Resolve the promise for the user's media stream audio alias if it exists.\n\n\n if (pendingMediaRequests) pendingMediaRequests.audio.resolve(audioStream);\n } // Add mediaStreams video streamName alias\n\n\n var videoTracks = stream.getVideoTracks();\n\n if (videoTracks.length > 0) {\n var videoStream = new MediaStream();\n\n try {\n videoTracks.forEach(function (track) {\n return videoStream.addTrack(track);\n });\n clientMediaStreams.video = videoStream;\n } catch (e) {\n NAF.log.warn(\"\".concat(clientId, \" setMediaStream \\\"video\\\" alias Error\"), e);\n } // Resolve the promise for the user's media stream video alias if it exists.\n\n\n if (pendingMediaRequests) pendingMediaRequests.video.resolve(videoStream);\n }\n } else {\n clientMediaStreams[streamName] = stream; // Resolve the promise for the user's media stream by StreamName if it exists.\n\n if (pendingMediaRequests && pendingMediaRequests[streamName]) {\n pendingMediaRequests[streamName].resolve(stream);\n }\n }\n }\n }, {\n key: \"addLocalMediaStream\",\n value: function addLocalMediaStream(stream, streamName) {\n var easyrtc = this.easyrtc;\n streamName = streamName || stream.id;\n this.setMediaStream(\"local\", stream, streamName);\n easyrtc.register3rdPartyLocalMediaStream(stream, streamName); // Add local stream to existing connections\n\n Object.keys(this.remoteClients).forEach(function (clientId) {\n if (easyrtc.getConnectStatus(clientId) !== easyrtc.NOT_CONNECTED) {\n easyrtc.addStreamToCall(clientId, streamName);\n }\n });\n }\n }, {\n key: \"removeLocalMediaStream\",\n value: function removeLocalMediaStream(streamName) {\n this.easyrtc.closeLocalMediaStream(streamName);\n delete this.mediaStreams[\"local\"][streamName];\n }\n }, {\n key: \"enableMicrophone\",\n value: function enableMicrophone(enabled) {\n this.easyrtc.enableMicrophone(enabled);\n }\n }, {\n key: \"enableCamera\",\n value: function enableCamera(enabled) {\n this.easyrtc.enableCamera(enabled);\n }\n }, {\n key: \"disconnect\",\n value: function disconnect() {\n this.easyrtc.disconnect();\n }\n /**\n * Privates\n */\n\n }, {\n key: \"_connect\",\n value: function _connect(connectSuccess, connectFailure) {\n var that = this;\n this.easyrtc.setStreamAcceptor(this.setMediaStream.bind(this));\n this.easyrtc.setOnStreamClosed(function (clientId, stream, streamName) {\n delete this.mediaStreams[clientId][streamName];\n });\n\n if (that.easyrtc.audioEnabled || that.easyrtc.videoEnabled) {\n navigator.mediaDevices.getUserMedia({\n video: that.easyrtc.videoEnabled,\n audio: that.easyrtc.audioEnabled\n }).then(function (stream) {\n that.addLocalMediaStream(stream, \"default\");\n that.easyrtc.connect(that.app, connectSuccess, connectFailure);\n }, function (errorCode, errmesg) {\n NAF.log.error(errorCode, errmesg);\n });\n } else {\n that.easyrtc.connect(that.app, connectSuccess, connectFailure);\n }\n }\n }, {\n key: \"_getRoomJoinTime\",\n value: function _getRoomJoinTime(clientId) {\n var myRoomId = NAF.room;\n var joinTime = this.easyrtc.getRoomOccupantsAsMap(myRoomId)[clientId].roomJoinTime;\n return joinTime;\n }\n }, {\n key: \"getServerTime\",\n value: function getServerTime() {\n return Date.now() + this.avgTimeOffset;\n }\n }]);\n\n return EasyRtcAdapter;\n}(NoOpAdapter);\n\nmodule.exports = EasyRtcAdapter;\n\n//# sourceURL=webpack://networked-aframe/./src/adapters/EasyRtcAdapter.js?"); +eval("function _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 _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 _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\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, \"prototype\", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } else if (call !== void 0) { throw new TypeError(\"Derived constructors may only return object or undefined\"); } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n/* global NAF */\nvar NoOpAdapter = __webpack_require__(/*! ./NoOpAdapter */ \"./src/adapters/NoOpAdapter.js\");\n\nvar EasyRtcAdapter = /*#__PURE__*/function (_NoOpAdapter) {\n _inherits(EasyRtcAdapter, _NoOpAdapter);\n\n var _super = _createSuper(EasyRtcAdapter);\n\n function EasyRtcAdapter(easyrtc) {\n var _this;\n\n _classCallCheck(this, EasyRtcAdapter);\n\n _this = _super.call(this);\n _this.easyrtc = easyrtc || window.easyrtc;\n _this.app = \"default\";\n _this.room = \"default\";\n _this.mediaStreams = {};\n _this.remoteClients = {};\n _this.pendingMediaRequests = new Map();\n _this.serverTimeRequests = 0;\n _this.timeOffsets = [];\n _this.avgTimeOffset = 0;\n\n _this.easyrtc.setPeerOpenListener(function (clientId) {\n var clientConnection = _this.easyrtc.getPeerConnectionByUserId(clientId);\n\n _this.remoteClients[clientId] = clientConnection;\n });\n\n _this.easyrtc.setPeerClosedListener(function (clientId) {\n delete _this.remoteClients[clientId];\n\n var pendingMediaRequests = _this.pendingMediaRequests.get(clientId);\n\n if (pendingMediaRequests) {\n var msg = \"The user disconnected before the media stream was resolved.\";\n Object.keys(pendingMediaRequests).forEach(function (streamName) {\n pendingMediaRequests[streamName].reject(msg);\n });\n\n _this.pendingMediaRequests[\"delete\"](clientId);\n }\n });\n\n return _this;\n }\n\n _createClass(EasyRtcAdapter, [{\n key: \"setServerUrl\",\n value: function setServerUrl(url) {\n this.easyrtc.setSocketUrl(url);\n }\n }, {\n key: \"setApp\",\n value: function setApp(appName) {\n this.app = appName;\n }\n }, {\n key: \"setRoom\",\n value: function setRoom(roomName) {\n this.room = roomName;\n this.easyrtc.joinRoom(roomName, null);\n } // options: { datachannel: bool, audio: bool, video: bool }\n\n }, {\n key: \"setWebRtcOptions\",\n value: function setWebRtcOptions(options) {\n // this.easyrtc.enableDebug(true);\n this.easyrtc.enableDataChannels(options.datachannel);\n this.easyrtc.enableVideo(options.video);\n this.easyrtc.enableAudio(options.audio); // TODO receive(audio|video) options ?\n\n this.easyrtc.enableVideoReceive(true);\n this.easyrtc.enableAudioReceive(true);\n }\n }, {\n key: \"setServerConnectListeners\",\n value: function setServerConnectListeners(successListener, failureListener) {\n this.connectSuccess = successListener;\n this.connectFailure = failureListener;\n }\n }, {\n key: \"setRoomOccupantListener\",\n value: function setRoomOccupantListener(occupantListener) {\n this.easyrtc.setRoomOccupantListener(function (roomName, occupants, primary) {\n occupantListener(occupants);\n });\n }\n }, {\n key: \"setDataChannelListeners\",\n value: function setDataChannelListeners(openListener, closedListener, messageListener) {\n this.easyrtc.setDataChannelOpenListener(openListener);\n this.easyrtc.setDataChannelCloseListener(closedListener);\n this.easyrtc.setPeerListener(messageListener);\n }\n }, {\n key: \"updateTimeOffset\",\n value: function updateTimeOffset() {\n var _this2 = this;\n\n var clientSentTime = Date.now() + this.avgTimeOffset;\n return fetch(document.location.href, {\n method: \"HEAD\",\n cache: \"no-cache\"\n }).then(function (res) {\n var precision = 1000;\n var serverReceivedTime = new Date(res.headers.get(\"Date\")).getTime() + precision / 2;\n var clientReceivedTime = Date.now();\n var serverTime = serverReceivedTime + (clientReceivedTime - clientSentTime) / 2;\n var timeOffset = serverTime - clientReceivedTime;\n _this2.serverTimeRequests++;\n\n if (_this2.serverTimeRequests <= 10) {\n _this2.timeOffsets.push(timeOffset);\n } else {\n _this2.timeOffsets[_this2.serverTimeRequests % 10] = timeOffset;\n }\n\n _this2.avgTimeOffset = _this2.timeOffsets.reduce(function (acc, offset) {\n return acc += offset;\n }, 0) / _this2.timeOffsets.length;\n\n if (_this2.serverTimeRequests > 10) {\n setTimeout(function () {\n return _this2.updateTimeOffset();\n }, 5 * 60 * 1000); // Sync clock every 5 minutes.\n } else {\n _this2.updateTimeOffset();\n }\n });\n }\n }, {\n key: \"connect\",\n value: function connect() {\n var _this3 = this;\n\n Promise.all([this.updateTimeOffset(), new Promise(function (resolve, reject) {\n _this3._connect(resolve, reject);\n })]).then(function (_ref) {\n var _ref2 = _slicedToArray(_ref, 2),\n _ = _ref2[0],\n clientId = _ref2[1];\n\n _this3._myRoomJoinTime = _this3._getRoomJoinTime(clientId);\n\n _this3.connectSuccess(clientId);\n })[\"catch\"](this.connectFailure);\n }\n }, {\n key: \"shouldStartConnectionTo\",\n value: function shouldStartConnectionTo(client) {\n return this._myRoomJoinTime <= client.roomJoinTime;\n }\n }, {\n key: \"startStreamConnection\",\n value: function startStreamConnection(clientId) {\n this.easyrtc.call(clientId, function (caller, media) {\n if (media === \"datachannel\") {\n NAF.log.write(\"Successfully started datachannel to \", caller);\n }\n }, function (errorCode, errorText) {\n NAF.log.error(errorCode, errorText);\n }, function (wasAccepted) {// console.log(\"was accepted=\" + wasAccepted);\n });\n }\n }, {\n key: \"closeStreamConnection\",\n value: function closeStreamConnection(clientId) {\n this.easyrtc.hangup(clientId);\n }\n }, {\n key: \"sendData\",\n value: function sendData(clientId, dataType, data) {\n // send via webrtc otherwise fallback to websockets\n this.easyrtc.sendData(clientId, dataType, data);\n }\n }, {\n key: \"sendDataGuaranteed\",\n value: function sendDataGuaranteed(clientId, dataType, data) {\n this.easyrtc.sendDataWS(clientId, dataType, data);\n }\n }, {\n key: \"broadcastData\",\n value: function broadcastData(dataType, data) {\n var roomOccupants = this.easyrtc.getRoomOccupantsAsMap(this.room); // Iterate over the keys of the easyrtc room occupants map.\n // getRoomOccupantsAsArray uses Object.keys which allocates memory.\n\n for (var roomOccupant in roomOccupants) {\n if (roomOccupants[roomOccupant] && roomOccupant !== this.easyrtc.myEasyrtcid) {\n // send via webrtc otherwise fallback to websockets\n this.easyrtc.sendData(roomOccupant, dataType, data);\n }\n }\n }\n }, {\n key: \"broadcastDataGuaranteed\",\n value: function broadcastDataGuaranteed(dataType, data) {\n var destination = {\n targetRoom: this.room\n };\n this.easyrtc.sendDataWS(destination, dataType, data);\n }\n }, {\n key: \"getConnectStatus\",\n value: function getConnectStatus(clientId) {\n var status = this.easyrtc.getConnectStatus(clientId);\n\n if (status == this.easyrtc.IS_CONNECTED) {\n return NAF.adapters.IS_CONNECTED;\n } else if (status == this.easyrtc.NOT_CONNECTED) {\n return NAF.adapters.NOT_CONNECTED;\n } else {\n return NAF.adapters.CONNECTING;\n }\n }\n }, {\n key: \"getMediaStream\",\n value: function getMediaStream(clientId) {\n var streamName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : \"audio\";\n\n if (this.mediaStreams[clientId] && this.mediaStreams[clientId][streamName]) {\n NAF.log.write(\"Already had \".concat(streamName, \" for \").concat(clientId));\n return Promise.resolve(this.mediaStreams[clientId][streamName]);\n } else {\n NAF.log.write(\"Waiting on \".concat(streamName, \" for \").concat(clientId)); // Create initial pendingMediaRequests with audio|video alias\n\n if (!this.pendingMediaRequests.has(clientId)) {\n var _pendingMediaRequests = {};\n var audioPromise = new Promise(function (resolve, reject) {\n _pendingMediaRequests.audio = {\n resolve: resolve,\n reject: reject\n };\n })[\"catch\"](function (e) {\n return NAF.log.warn(\"\".concat(clientId, \" getMediaStream Audio Error\"), e);\n });\n _pendingMediaRequests.audio.promise = audioPromise;\n var videoPromise = new Promise(function (resolve, reject) {\n _pendingMediaRequests.video = {\n resolve: resolve,\n reject: reject\n };\n })[\"catch\"](function (e) {\n return NAF.log.warn(\"\".concat(clientId, \" getMediaStream Video Error\"), e);\n });\n _pendingMediaRequests.video.promise = videoPromise;\n this.pendingMediaRequests.set(clientId, _pendingMediaRequests);\n }\n\n var pendingMediaRequests = this.pendingMediaRequests.get(clientId); // Create initial pendingMediaRequests with streamName\n\n if (!pendingMediaRequests[streamName]) {\n var streamPromise = new Promise(function (resolve, reject) {\n pendingMediaRequests[streamName] = {\n resolve: resolve,\n reject: reject\n };\n })[\"catch\"](function (e) {\n return NAF.log.warn(\"\".concat(clientId, \" getMediaStream \\\"\").concat(streamName, \"\\\" Error\"), e);\n });\n pendingMediaRequests[streamName].promise = streamPromise;\n }\n\n return this.pendingMediaRequests.get(clientId)[streamName].promise;\n }\n }\n }, {\n key: \"setMediaStream\",\n value: function setMediaStream(clientId, stream, streamName) {\n var pendingMediaRequests = this.pendingMediaRequests.get(clientId); // return undefined if there is no entry in the Map\n\n var clientMediaStreams = this.mediaStreams[clientId] = this.mediaStreams[clientId] || {};\n\n if (streamName === \"default\") {\n // Safari doesn't like it when you use a mixed media stream where one of the tracks is inactive, so we\n // split the tracks into two streams.\n // Add mediaStreams audio streamName alias\n var audioTracks = stream.getAudioTracks();\n\n if (audioTracks.length > 0) {\n var audioStream = new MediaStream();\n\n try {\n audioTracks.forEach(function (track) {\n return audioStream.addTrack(track);\n });\n clientMediaStreams.audio = audioStream;\n } catch (e) {\n NAF.log.warn(\"\".concat(clientId, \" setMediaStream \\\"audio\\\" alias Error\"), e);\n } // Resolve the promise for the user's media stream audio alias if it exists.\n\n\n if (pendingMediaRequests) pendingMediaRequests.audio.resolve(audioStream);\n } // Add mediaStreams video streamName alias\n\n\n var videoTracks = stream.getVideoTracks();\n\n if (videoTracks.length > 0) {\n var videoStream = new MediaStream();\n\n try {\n videoTracks.forEach(function (track) {\n return videoStream.addTrack(track);\n });\n clientMediaStreams.video = videoStream;\n } catch (e) {\n NAF.log.warn(\"\".concat(clientId, \" setMediaStream \\\"video\\\" alias Error\"), e);\n } // Resolve the promise for the user's media stream video alias if it exists.\n\n\n if (pendingMediaRequests) pendingMediaRequests.video.resolve(videoStream);\n }\n } else {\n clientMediaStreams[streamName] = stream; // Resolve the promise for the user's media stream by StreamName if it exists.\n\n if (pendingMediaRequests && pendingMediaRequests[streamName]) {\n pendingMediaRequests[streamName].resolve(stream);\n }\n }\n }\n }, {\n key: \"addLocalMediaStream\",\n value: function addLocalMediaStream(stream, streamName) {\n var easyrtc = this.easyrtc;\n streamName = streamName || stream.id;\n this.setMediaStream(\"local\", stream, streamName);\n easyrtc.register3rdPartyLocalMediaStream(stream, streamName); // Add local stream to existing connections\n\n Object.keys(this.remoteClients).forEach(function (clientId) {\n if (easyrtc.getConnectStatus(clientId) !== easyrtc.NOT_CONNECTED) {\n easyrtc.addStreamToCall(clientId, streamName);\n }\n });\n }\n }, {\n key: \"removeLocalMediaStream\",\n value: function removeLocalMediaStream(streamName) {\n this.easyrtc.closeLocalMediaStream(streamName);\n delete this.mediaStreams[\"local\"][streamName];\n }\n }, {\n key: \"enableMicrophone\",\n value: function enableMicrophone(enabled) {\n this.easyrtc.enableMicrophone(enabled);\n }\n }, {\n key: \"enableCamera\",\n value: function enableCamera(enabled) {\n this.easyrtc.enableCamera(enabled);\n }\n }, {\n key: \"disconnect\",\n value: function disconnect() {\n this.easyrtc.disconnect();\n }\n /**\n * Privates\n */\n\n }, {\n key: \"_connect\",\n value: function _connect(connectSuccess, connectFailure) {\n var that = this;\n this.easyrtc.setStreamAcceptor(this.setMediaStream.bind(this));\n this.easyrtc.setOnStreamClosed(function (clientId, stream, streamName) {\n if (streamName === \"default\") {\n delete that.mediaStreams[clientId].audio;\n delete that.mediaStreams[clientId].video;\n } else {\n delete that.mediaStreams[clientId][streamName];\n }\n\n if (Object.keys(that.mediaStreams[clientId]).length === 0) {\n delete that.mediaStreams[clientId];\n }\n });\n\n if (that.easyrtc.audioEnabled || that.easyrtc.videoEnabled) {\n navigator.mediaDevices.getUserMedia({\n video: that.easyrtc.videoEnabled,\n audio: that.easyrtc.audioEnabled\n }).then(function (stream) {\n that.addLocalMediaStream(stream, \"default\");\n that.easyrtc.connect(that.app, connectSuccess, connectFailure);\n }, function (errorCode, errmesg) {\n NAF.log.error(errorCode, errmesg);\n });\n } else {\n that.easyrtc.connect(that.app, connectSuccess, connectFailure);\n }\n }\n }, {\n key: \"_getRoomJoinTime\",\n value: function _getRoomJoinTime(clientId) {\n var myRoomId = NAF.room;\n var joinTime = this.easyrtc.getRoomOccupantsAsMap(myRoomId)[clientId].roomJoinTime;\n return joinTime;\n }\n }, {\n key: \"getServerTime\",\n value: function getServerTime() {\n return Date.now() + this.avgTimeOffset;\n }\n }]);\n\n return EasyRtcAdapter;\n}(NoOpAdapter);\n\nmodule.exports = EasyRtcAdapter;\n\n//# sourceURL=webpack://networked-aframe/./src/adapters/EasyRtcAdapter.js?"); /***/ }), diff --git a/dist/networked-aframe.min.js b/dist/networked-aframe.min.js index eb17502f..7ef01121 100644 --- a/dist/networked-aframe.min.js +++ b/dist/networked-aframe.min.js @@ -1 +1 @@ -(()=>{var e={80:e=>{"use strict";var t=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:0,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:.15;n(this,e),this.state=0,this.buffer=[],this.bufferTime=1e3*i,this.time=0,this.mode=t,this.originFrame=o(),this.position=new THREE.Vector3,this.quaternion=new THREE.Quaternion,this.scale=new THREE.Vector3(1,1,1)}return t(e,[{key:"hermite",value:function(e,t,n,i,o,r){var a=t*t,s=t*t*t,c=2*s-3*a+1,u=-2*s+3*a,l=s-2*a+t,d=s-a;e.copy(n.multiplyScalar(c)),e.add(i.multiplyScalar(u)),e.add(o.multiplyScalar(l)),e.add(r.multiplyScalar(d))}},{key:"lerp",value:function(e,t,n,i){e.lerpVectors(t,n,i)}},{key:"slerp",value:function(e,t,n,i){e.slerpQuaternions(t,n,i)}},{key:"updateOriginFrameToBufferTail",value:function(){var e;e=this.originFrame,i.push(e),this.originFrame=this.buffer.shift()}},{key:"appendBuffer",value:function(e,t,n,i){var r=this.buffer.length>0?this.buffer[this.buffer.length-1]:null;if(r&&r.time===this.time)e&&r.position.copy(e),t&&r.velocity.copy(t),n&&r.quaternion.copy(n),i&&r.scale.copy(i);else{var a=r||this.originFrame,s=o();s.position.copy(e||a.position),s.velocity.copy(t||a.velocity),s.quaternion.copy(n||a.quaternion),s.scale.copy(i||a.scale),s.time=this.time,this.buffer.push(s)}}},{key:"setTarget",value:function(e,t,n,i){this.appendBuffer(e,t,n,i)}},{key:"setPosition",value:function(e,t){this.appendBuffer(e,t,null,null)}},{key:"setQuaternion",value:function(e){this.appendBuffer(null,null,e,null)}},{key:"setScale",value:function(e){this.appendBuffer(null,null,null,e)}},{key:"update",value:function(e){if(0===this.state&&this.buffer.length>0&&(this.updateOriginFrameToBufferTail(),this.position.copy(this.originFrame.position),this.quaternion.copy(this.originFrame.quaternion),this.scale.copy(this.originFrame.scale),this.state=1),1===this.state&&this.buffer.length>0&&this.time>this.bufferTime&&(this.state=2),2===this.state){for(var t=this.time-this.bufferTime;this.buffer.length>0&&t>this.buffer[0].time;)this.buffer.length>1?this.updateOriginFrameToBufferTail():(this.originFrame.position.copy(this.buffer[0].position),this.originFrame.velocity.copy(this.buffer[0].velocity),this.originFrame.quaternion.copy(this.buffer[0].quaternion),this.originFrame.scale.copy(this.buffer[0].scale),this.originFrame.time=this.buffer[0].time,this.buffer[0].time=this.time+e);if(this.buffer.length>0&&this.buffer[0].time>0){var n=this.buffer[0],i=n.time-this.originFrame.time,o=(t-this.originFrame.time)/i;0===this.mode?this.lerp(this.position,this.originFrame.position,n.position,o):1===this.mode&&this.hermite(this.position,o,this.originFrame.position,n.position,this.originFrame.velocity.multiplyScalar(i),n.velocity.multiplyScalar(i)),this.slerp(this.quaternion,this.originFrame.quaternion,n.quaternion,o),this.lerp(this.scale,this.originFrame.scale,n.scale,o)}}0!==this.state&&(this.time+=e)}},{key:"getPosition",value:function(){return this.position}},{key:"getQuaternion",value:function(){return this.quaternion}},{key:"getScale",value:function(){return this.scale}}]),e}();e.exports=r},325:e=>{function t(e,t){for(var n=0;n{"use strict";function t(e){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t(e)}var n=Array.isArray,i=Object.keys,o=Object.prototype.hasOwnProperty;e.exports=function e(r,a){if(r===a)return!0;if(r&&a&&"object"==t(r)&&"object"==t(a)){var s,c,u,l=n(r),d=n(a);if(l&&d){if((c=r.length)!=a.length)return!1;for(s=c;0!=s--;)if(!e(r[s],a[s]))return!1;return!0}if(l!=d)return!1;var h=r instanceof Date,f=a instanceof Date;if(h!=f)return!1;if(h&&f)return r.getTime()==a.getTime();var p=r instanceof RegExp,m=a instanceof RegExp;if(p!=m)return!1;if(p&&m)return r.toString()==a.toString();var v=i(r);if((c=v.length)!==i(a).length)return!1;for(s=c;0!=s--;)if(!o.call(a,v[s]))return!1;for(s=c;0!=s--;)if(!e(r[u=v[s]],a[u]))return!1;return!0}return r!=r&&a!=a}},520:(e,t,n)=>{var i=n(998),o=n(648),r=n(452),a=n(565),s=n(390),c=n(371),u=n(267),l={app:"",room:"",clientId:""};l.options=i,l.utils=o,l.log=new r,l.schemas=new a,l.version="0.9.0",l.adapters=new u;var d=new s,h=new c(d);l.connection=h,l.entities=d,e.exports=window.NAF=l},367:e=>{function t(e,t){for(var n=0;n{function t(e,t){for(var n=0;n{function t(e,t){for(var n=0;n3&&void 0!==arguments[3]&&arguments[3],o=arguments.length>4&&void 0!==arguments[4]&&arguments[4];NAF.app=t,NAF.room=n,this.adapter.setServerUrl(e),this.adapter.setApp(t),this.adapter.setRoom(n);var r={audio:i,video:o,datachannel:!0};return this.adapter.setWebRtcOptions(r),this.adapter.setServerConnectListeners(this.connectSuccess.bind(this),this.connectFailure.bind(this)),this.adapter.setDataChannelListeners(this.dataChannelOpen.bind(this),this.dataChannelClosed.bind(this),this.receivedData.bind(this)),this.adapter.setRoomOccupantListener(this.occupantsReceived.bind(this)),this.adapter.connect()}},{key:"onConnect",value:function(e){this.onConnectCallback=e,this.isConnected()?e():document.body.addEventListener("connected",e,!1)}},{key:"connectSuccess",value:function(e){NAF.log.write("Networked-Aframe Client ID:",e),NAF.clientId=e;var t=new CustomEvent("connected",{detail:{clientId:e}});document.body.dispatchEvent(t)}},{key:"connectFailure",value:function(e,t){NAF.log.error(e,"failure to connect")}},{key:"occupantsReceived",value:function(e){var t=Object.assign({},this.connectedClients);this.connectedClients=e,this.checkForDisconnectingClients(t,e),this.checkForConnectingClients(e)}},{key:"checkForDisconnectingClients",value:function(e,t){for(var n in e)t[n]||(NAF.log.write("Closing stream to",n),this.adapter.closeStreamConnection(n))}},{key:"checkForConnectingClients",value:function(e){for(var t in e)this.isNewClient(t)&&this.adapter.shouldStartConnectionTo(e[t])&&(NAF.log.write("Opening datachannel to",t),this.adapter.startStreamConnection(t))}},{key:"getConnectedClients",value:function(){return this.connectedClients}},{key:"isConnected",value:function(){return!!NAF.clientId}},{key:"isMineAndConnected",value:function(e){return this.isConnected()&&NAF.clientId===e}},{key:"isNewClient",value:function(e){return!this.isConnectedTo(e)}},{key:"isConnectedTo",value:function(e){return this.adapter.getConnectStatus(e)===NAF.adapters.IS_CONNECTED}},{key:"dataChannelOpen",value:function(e){NAF.log.write("Opened data channel from "+e),this.activeDataChannels[e]=!0,this.entities.completeSync(e,!0);var t=new CustomEvent("clientConnected",{detail:{clientId:e}});document.body.dispatchEvent(t)}},{key:"dataChannelClosed",value:function(e){NAF.log.write("Closed data channel from "+e),this.activeDataChannels[e]=!1,this.entities.removeEntitiesOfClient(e);var t=new CustomEvent("clientDisconnected",{detail:{clientId:e}});document.body.dispatchEvent(t)}},{key:"hasActiveDataChannel",value:function(e){return!!this.activeDataChannels[e]}},{key:"broadcastData",value:function(e,t){this.adapter.broadcastData(e,t)}},{key:"broadcastDataGuaranteed",value:function(e,t){this.adapter.broadcastDataGuaranteed(e,t)}},{key:"sendData",value:function(e,t,n,i){this.hasActiveDataChannel(e)&&(i?this.adapter.sendDataGuaranteed(e,t,n):this.adapter.sendData(e,t,n))}},{key:"sendDataGuaranteed",value:function(e,t,n){this.sendData(e,t,n,!0)}},{key:"subscribeToDataChannel",value:function(e,t){this.isReservedDataType(e)?NAF.log.error("NetworkConnection@subscribeToDataChannel: "+e+" is a reserved dataType. Choose another"):this.dataChannelSubs[e]=t}},{key:"unsubscribeToDataChannel",value:function(e){this.isReservedDataType(e)?NAF.log.error("NetworkConnection@unsubscribeToDataChannel: "+e+" is a reserved dataType. Choose another"):delete this.dataChannelSubs[e]}},{key:"isReservedDataType",value:function(e){return"u"==e||"r"==e}},{key:"receivedData",value:function(e,t,n,i){this.dataChannelSubs[t]?this.dataChannelSubs[t](e,t,n,i):NAF.log.write("NetworkConnection@receivedData: "+t+" has not been subscribed to yet. Call subscribeToDataChannel()")}},{key:"getServerTime",value:function(){return this.adapter.getServerTime()}},{key:"disconnect",value:function(){this.entities.removeRemoteEntities(),this.adapter&&this.adapter.disconnect(),NAF.app="",NAF.room="",NAF.clientId="",this.connectedClients={},this.activeDataChannels={},this.adapter=null,this.setupDefaultDataSubscriptions(),document.body.removeEventListener("connected",this.onConnectCallback)}}],i&&t(n.prototype,i),Object.defineProperty(n,"prototype",{writable:!1}),e}();e.exports=n},390:(e,t,n)=>{function i(e,t){for(var n=0;n{function t(e,t){for(var n=0;n is defined."));if(!this.validateTemplate(e,t))return;this.templateCache[e.template]=document.importNode(t.content,!0)}else NAF.log.error("Schema not valid: ",e),NAF.log.error("See https://github.com/networked-aframe/networked-aframe#syncing-custom-components")}},{key:"getCachedTemplate",value:function(e){return this.templateIsCached(e)||(this.templateExistsInScene(e)?this.add(this.createDefaultSchema(e)):NAF.log.error("Template el for ".concat(e," is not in the scene, add the template to and register with NAF.schemas.add."))),this.templateCache[e].firstElementChild.cloneNode(!0)}},{key:"templateIsCached",value:function(e){return!!this.templateCache[e]}},{key:"getComponents",value:function(e){var t=["position","rotation"];return this.hasTemplate(e)&&(t=this.schemaDict[e].components),t}},{key:"hasTemplate",value:function(e){return!!this.schemaDict[e]}},{key:"templateExistsInScene",value:function(e){var t=document.querySelector(e);return t&&this.isTemplateTag(t)}},{key:"validateSchema",value:function(e){return!(!e.template||!e.components)}},{key:"validateTemplate",value:function(e,t){return this.isTemplateTag(t)?!!this.templateHasOneOrZeroChildren(t)||(NAF.log.error("Template for ".concat(e.template," has more than one child. Templates must have one direct child element, no more. Template found:"),t),!1):(NAF.log.error("Template for ".concat(e.template," is not a