UNPKG

timing-provider

Version:

An implementation of the timing provider specification.

1,044 lines (1,016 loc) 69.2 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@babel/runtime/helpers/slicedToArray'), require('timing-object'), require('@babel/runtime/helpers/classCallCheck'), require('@babel/runtime/helpers/createClass'), require('@babel/runtime/helpers/toConsumableArray'), require('rxjs'), require('subscribable-things'), require('@babel/runtime/helpers/objectWithoutProperties'), require('@babel/runtime/helpers/defineProperty'), require('@babel/runtime/helpers/possibleConstructorReturn'), require('@babel/runtime/helpers/getPrototypeOf'), require('@babel/runtime/helpers/inherits'), require('rxjs-etc/operators'), require('@babel/runtime/helpers/typeof'), require('@babel/runtime/helpers/toArray'), require('rxjs-etc'), require('@babel/runtime/helpers/asyncToGenerator'), require('@babel/runtime/regenerator')) : typeof define === 'function' && define.amd ? define(['exports', '@babel/runtime/helpers/slicedToArray', 'timing-object', '@babel/runtime/helpers/classCallCheck', '@babel/runtime/helpers/createClass', '@babel/runtime/helpers/toConsumableArray', 'rxjs', 'subscribable-things', '@babel/runtime/helpers/objectWithoutProperties', '@babel/runtime/helpers/defineProperty', '@babel/runtime/helpers/possibleConstructorReturn', '@babel/runtime/helpers/getPrototypeOf', '@babel/runtime/helpers/inherits', 'rxjs-etc/operators', '@babel/runtime/helpers/typeof', '@babel/runtime/helpers/toArray', 'rxjs-etc', '@babel/runtime/helpers/asyncToGenerator', '@babel/runtime/regenerator'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.timingProvider = {}, global._slicedToArray, global.timingObject, global._classCallCheck, global._createClass, global._toConsumableArray, global.rxjs, global.subscribableThings, global._objectWithoutProperties, global._defineProperty, global._possibleConstructorReturn, global._getPrototypeOf, global._inherits, global.operators, global._typeof, global._toArray, global.rxjsEtc, global._asyncToGenerator, global._regeneratorRuntime)); })(this, (function (exports, _slicedToArray, timingObject, _classCallCheck, _createClass, _toConsumableArray, rxjs, subscribableThings, _objectWithoutProperties, _defineProperty, _possibleConstructorReturn, _getPrototypeOf, _inherits, operators, _typeof, _toArray, rxjsEtc, _asyncToGenerator, _regeneratorRuntime) { 'use strict'; var createEventTargetConstructor = function createEventTargetConstructor(createEventTarget, wrapEventListener) { return /*#__PURE__*/function () { function EventTarget() { _classCallCheck(this, EventTarget); this._listeners = new WeakMap(); this._nativeEventTarget = createEventTarget(); } return _createClass(EventTarget, [{ key: "addEventListener", value: function addEventListener(type, listener, options) { if (listener !== null) { var wrappedEventListener = this._listeners.get(listener); if (wrappedEventListener === undefined) { wrappedEventListener = wrapEventListener(this, listener); if (typeof listener === 'function') { this._listeners.set(listener, wrappedEventListener); } } this._nativeEventTarget.addEventListener(type, wrappedEventListener, options); } } }, { key: "dispatchEvent", value: function dispatchEvent(event) { return this._nativeEventTarget.dispatchEvent(event); } }, { key: "removeEventListener", value: function removeEventListener(type, listener, options) { var wrappedEventListener = listener === null ? undefined : this._listeners.get(listener); this._nativeEventTarget.removeEventListener(type, wrappedEventListener === undefined ? null : wrappedEventListener, options); } }]); }(); }; var createEventTargetFactory = function createEventTargetFactory(window) { return function () { if (window === null) { throw new Error('A native EventTarget could not be created.'); } return window.document.createElement('p'); }; }; var createRTCPeerConnectionFactory = function createRTCPeerConnectionFactory(window) { return function () { if (window === null) { throw new Error('A native EventTarget could not be created.'); } return new window.RTCPeerConnection({ iceCandidatePoolSize: 1, iceServers: [{ urls: ['stun:stun.l.google.com:19302', 'stun:stun1.l.google.com:19302'] }] }); }; }; var createSignalingFactory = function createSignalingFactory(createWebSocket) { return function (url) { var errorSubject = new rxjs.Subject(); var webSocket = createWebSocket(url); var signalingEvent$ = rxjs.merge(subscribableThings.on(webSocket, 'message'), rxjs.merge(rxjs.merge.apply(void 0, _toConsumableArray(['close', 'error'].map(function (type) { return subscribableThings.on(webSocket, type); }))).pipe(rxjs.map(function (_ref) { var type = _ref.type; return new Error("WebSocket fired unexpected event of type \"".concat(type, "\".")); })), errorSubject // tslint:disable-next-line:rxjs-throw-error ).pipe(rxjs.mergeMap(function (err) { return rxjs.throwError(function () { return err; }); }))).pipe(rxjs.finalize(function () { return webSocket.close(); }), rxjs.map(function (event) { return JSON.parse(event.data); })); var sendSignalingEvent = function sendSignalingEvent(event) { try { webSocket.send(JSON.stringify(event)); } catch (err) { errorSubject.next(err); } }; return [signalingEvent$, sendSignalingEvent]; }; }; var createSortByHopsAndRoundTripTime = function createSortByHopsAndRoundTripTime(compareHops, getHops, getRoundTripTime) { return function (array) { array.sort(function (a, b) { var result = compareHops(getHops(a), getHops(b)); if (result === 0) { return getRoundTripTime(a) - getRoundTripTime(b); } return result; }); }; }; var findSendPeerToPeerMessageFunction = function findSendPeerToPeerMessageFunction(key, sendPeerToPeerMessageTuples) { var sendPeerToPeerMessageTuple = sendPeerToPeerMessageTuples.find(function (_ref) { var _ref2 = _slicedToArray(_ref, 1), clientId = _ref2[0]; return clientId === key; }); if (sendPeerToPeerMessageTuple === undefined) { throw new Error('There is no tuple with the given key.'); } return sendPeerToPeerMessageTuple[1]; }; var isBooleanTuple = function isBooleanTuple(tuple) { return typeof tuple[1] === 'boolean'; }; var isFalseTuple = function isFalseTuple(tuple) { return tuple[1] === false; }; var isNotBooleanTuple = function isNotBooleanTuple(tuple) { return typeof tuple[1] !== 'boolean'; }; var isPeerToPeerMessageTuple = function isPeerToPeerMessageTuple(tuple) { return tuple[1] !== null && _typeof(tuple[1]) === 'object'; }; var isSendPeerToPeerMessageTuple = function isSendPeerToPeerMessageTuple(tuple) { return typeof tuple[1] === 'function'; }; var isTrueTuple = function isTrueTuple(tuple) { return tuple[1] === true; }; var INITIAL_VALUE = Symbol(); var combineAsTuple = function combineAsTuple() { return function (source) { return source.pipe(rxjs.scan(function (lastValue, _ref) { var _ref2 = _slicedToArray(_ref, 2), index = _ref2[0], value = _ref2[1]; if (index === 0) { return [value, lastValue[1]]; } return [lastValue[0], value]; }, [INITIAL_VALUE, INITIAL_VALUE]), rxjs.filter(function (tuple) { return tuple.every(function (element) { return element !== INITIAL_VALUE; }); })); }; }; /* * This will compute the offset with the formula `remoteTime - localTime`. That means a positive offset indicates that `remoteTime` is * larger than `localTime` and viceversa. */ var computeOffsetAndRoundTripTime = function computeOffsetAndRoundTripTime() { return rxjs.map(function (_ref) { var _ref2 = _slicedToArray(_ref, 4), localSentTime = _ref2[0], remoteReceivedTime = _ref2[1], remoteSentTime = _ref2[2], localReceivedTime = _ref2[3]; return [(remoteReceivedTime + remoteSentTime - localSentTime - localReceivedTime) / 2, localReceivedTime - localSentTime + remoteReceivedTime - remoteSentTime]; }); }; var ultimately = function ultimately(callback) { return function (source) { return new rxjs.Observable(function (observer) { var subscription = source.subscribe({ complete: function complete() { callback(); observer.complete(); }, error: function error(err) { callback(); observer.error(err); }, next: function next(value) { return observer.next(value); } }); return function () { callback(); subscription.unsubscribe(); }; }); }; }; var demultiplexMessages = function demultiplexMessages(getClientId, timer) { return function (source) { return new rxjs.Observable(function (observer) { var subjects = new Map(); var completeAll = function completeAll() { subjects.forEach(function (_ref) { var _ref2 = _slicedToArray(_ref, 2), subject = _ref2[0], subscription = _ref2[1]; if (subject === null) { subscription.unsubscribe(); } else { subject.complete(); } }); }; var isActive = function isActive(remoteClientId) { return getClientId() < remoteClientId; }; return source.pipe(ultimately(function () { return completeAll(); })).subscribe({ complete: function complete() { observer.complete(); }, error: function error(err) { observer.error(err); }, next: function next(event) { var _a; var remoteClientId = event.client.id; var _ref3 = (_a = subjects.get(remoteClientId)) !== null && _a !== void 0 ? _a : [null, null], _ref4 = _slicedToArray(_ref3, 2), subject = _ref4[0], subscription = _ref4[1]; if (event.type === 'termination') { if (subscription !== null) { subscription.unsubscribe(); } if (subject !== null) { subject.complete(); } subjects.set(remoteClientId, [null, timer.pipe(rxjs.skip(isActive(remoteClientId) ? 1 : 0), rxjs.take(1)).subscribe(function () { return subjects["delete"](remoteClientId); }) // tslint:disable-line:rxjs-no-nested-subscribe ]); } else if (subject === null && subscription === null) { var newSubject = new rxjs.Subject(); subjects.set(remoteClientId, [newSubject, null]); observer.next([remoteClientId, isActive(remoteClientId), newSubject.asObservable()]); newSubject.next(event); } else if (subscription === null) { subject.next(event); } } }); }); }; }; var enforceOrder = function enforceOrder(isFirstValue) { return function (source) { return source.pipe(rxjs.scan(function (_ref, value) { var _ref2 = _slicedToArray(_ref, 2), values = _ref2[0], bufferedValues = _ref2[1]; if (isFirstValue(value)) { if (bufferedValues === null) { throw new Error('Another value has been identified as the first value already.'); } return [[value].concat(_toConsumableArray(bufferedValues)), null]; } if (bufferedValues === null) { return [[value], bufferedValues]; } return [values, [].concat(_toConsumableArray(bufferedValues), [value])]; }, [[], []]), rxjs.concatMap(function (_ref3) { var _ref4 = _slicedToArray(_ref3, 1), values = _ref4[0]; return rxjs.from(values); })); }; }; var groupByProperty = function groupByProperty(property) { return rxjs.groupBy(function (value) { return value[property]; }); }; function _arrayLikeToArray$2(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } var matchPongWithPing = function matchPongWithPing(localSentTimesSubject) { return function (source) { return source.pipe(rxjs.withLatestFrom(localSentTimesSubject), rxjs.map(function (_ref) { var _ref2 = _slicedToArray(_ref, 2), _ref2$ = _ref2[0], index = _ref2$.index, remoteReceivedTime = _ref2$.remoteReceivedTime, remoteSentTime = _ref2$.remoteSentTime, timestamp = _ref2$.timestamp, _ref2$2 = _slicedToArray(_ref2[1], 2), startIndex = _ref2$2[0], localSentTimes = _ref2$2[1]; if (index < startIndex) { return null; } var numberOfMissingPings = index - startIndex; var _localSentTimes$slice = localSentTimes.slice(numberOfMissingPings), _localSentTimes$slice2 = _toArray(_localSentTimes$slice), localSentTime = _localSentTimes$slice2[0], unansweredPings = _arrayLikeToArray$2(_localSentTimes$slice2).slice(1); localSentTimesSubject.next([startIndex + numberOfMissingPings + 1, unansweredPings]); return [localSentTime, remoteReceivedTime, remoteSentTime, timestamp]; }), rxjs.filter(rxjsEtc.isNotNullish)); }; }; var createBackoff = function createBackoff(base) { return [function () { return Math.pow(base, 2); }, function () { // tslint:disable-next-line:no-parameter-reassignment base += 1; }]; }; var echo = function echo(callback, predicate, timer) { return function (source) { return source.pipe(rxjs.materialize(), rxjs.startWith(null), rxjs.switchMap(function (notification) { return rxjs.concat(rxjs.of(notification), notification === null || notification.kind === 'N' ? timer.pipe(rxjs.takeWhile(predicate), rxjs.tap(callback), rxjs.ignoreElements()) : rxjs.EMPTY); }), rxjs.filter(rxjsEtc.isNotNullish), rxjs.dematerialize()); }; }; var ignoreLateResult = function ignoreLateResult(promise) { return new rxjs.Observable(function (observer) { var isActive = true; promise.then(function (value) { if (isActive) { observer.next(value); observer.complete(); } }, function (err) { if (isActive) { observer.error(err); } }); return function () { return isActive = false; }; }); }; function ownKeys$2(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread$2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$2(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$2(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } var negotiateDataChannels = function negotiateDataChannels(createPeerConnection, sendSignalingEvent) { return function (source) { return source.pipe(rxjs.mergeMap(function (_ref) { var _ref2 = _slicedToArray(_ref, 3), clientId = _ref2[0], isActive = _ref2[1], observable = _ref2[2]; return new rxjs.Observable(function (observer) { var errorEvents = []; var errorSubject = new rxjs.Subject(); var receivedCandidates = []; var resetSubject = new rxjs.Subject(); var createAndSendOffer = function createAndSendOffer() { isFresh = false; return ignoreLateResult(peerConnection.setLocalDescription()).pipe(rxjs.tap(function () { var _peerConnection = peerConnection, localDescription = _peerConnection.localDescription; if (localDescription === null) { throw new Error('The local description is not set.'); } sendSignalingEvent(_objectSpread$2(_objectSpread$2({}, jsonifyDescription(localDescription)), {}, { client: { id: clientId }, version: version })); })); }; var subscribeToCandidates = function subscribeToCandidates() { return subscribableThings.on(peerConnection, 'icecandidate')(function (_ref3) { var candidate = _ref3.candidate; if (candidate === null) { sendSignalingEvent({ client: { id: clientId }, numberOfGatheredCandidates: numberOfGatheredCandidates, type: 'summary', version: version }); } else if (candidate.port !== 9 && candidate.protocol !== 'tcp') { sendSignalingEvent(_objectSpread$2(_objectSpread$2({}, candidate.toJSON()), {}, { client: { id: clientId }, type: 'candidate', version: version })); numberOfGatheredCandidates += 1; } }); }; var subscribeToDataChannels = function subscribeToDataChannels() { var subscriptions = [rxjs.zip([subscribableThings.on(reliableDataChannel, 'open'), subscribableThings.on(unreliableDataChannel, 'open')]).pipe(rxjs.take(1)).subscribe(function () { send = function send(event) { var dataChannel = event.type === 'update' ? reliableDataChannel : unreliableDataChannel; try { dataChannel.send(JSON.stringify(event)); } catch (err) { errorSubject.next(err); return false; } return true; }; observer.next([clientId, send]); }), rxjs.merge.apply(void 0, _toConsumableArray([reliableDataChannel, unreliableDataChannel].map(function (dataChannel) { return ['close', 'closing', 'error'].map(function (type) { return subscribableThings.on(dataChannel, type); }); }).flat())).subscribe(function (_ref4) { var type = _ref4.type; return errorSubject.next(new Error("RTCDataChannel fired unexpected event of type \"".concat(type, "\"."))); })]; var unsubscribeFunctions = [function () { return subscriptions.forEach(function (subscription) { return subscription.unsubscribe(); }); }, subscribableThings.on(reliableDataChannel, 'message')(function (_ref5) { var data = _ref5.data; var event = JSON.parse(data); observer.next([clientId, event]); }), subscribableThings.on(unreliableDataChannel, 'message')(function (_ref6) { var data = _ref6.data, timeStamp = _ref6.timeStamp; var event = _objectSpread$2(_objectSpread$2({}, JSON.parse(data)), {}, { timestamp: timeStamp !== null && timeStamp !== void 0 ? timeStamp : performance.now() }); observer.next([clientId, event]); })]; return function () { return unsubscribeFunctions.forEach(function (unsubscribeFunction) { return unsubscribeFunction(); }); }; }; var _createBackoff = createBackoff(1), _createBackoff2 = _slicedToArray(_createBackoff, 2), getBackoff = _createBackoff2[0], incrementBackoff = _createBackoff2[1]; var subscribeToPeerConnection = function subscribeToPeerConnection() { var subscription = rxjs.merge(subscribableThings.on(peerConnection, 'icecandidate'), subscribableThings.on(peerConnection, 'icegatheringstatechange')).pipe(rxjs.switchMap(function () { return rxjs.iif(function () { return peerConnection.iceGatheringState === 'gathering'; }, rxjs.defer(function () { return rxjs.timer(10000 * getBackoff()); }), rxjs.EMPTY); })).subscribe(function () { incrementBackoff(); errorSubject.next(new Error('RTCPeerConnection seems to be stuck at iceGatheringState "gathering".')); }); var unsubscribeFunctions = [function () { return subscription.unsubscribe(); }, subscribableThings.on(peerConnection, 'connectionstatechange')(function () { var connectionState = peerConnection.connectionState; if (['closed', 'disconnected', 'failed'].includes(connectionState)) { errorSubject.next(new Error("RTCPeerConnection transitioned to unexpected connectionState \"".concat(connectionState, "\"."))); } }), subscribableThings.on(peerConnection, 'icecandidateerror')(function (_ref7) { var address = _ref7.address, errorCode = _ref7.errorCode, errorText = _ref7.errorText, port = _ref7.port, url = _ref7.url; return sendSignalingEvent({ address: address, errorCode: errorCode, errorText: errorText, port: port, type: 'icecandidateerror', url: url }); }), subscribableThings.on(peerConnection, 'iceconnectionstatechange')(function () { var iceConnectionState = peerConnection.iceConnectionState; if (['closed', 'disconnected', 'failed'].includes(iceConnectionState)) { errorSubject.next(new Error("RTCPeerConnection transitioned to unexpected iceConnectionState \"".concat(iceConnectionState, "\"."))); } }), subscribableThings.on(peerConnection, 'signalingstatechange')(function () { if (peerConnection.signalingState === 'closed') { errorSubject.next(new Error("RTCPeerConnection transitioned to unexpected signalingState \"closed\".")); } })]; return function () { return unsubscribeFunctions.forEach(function (unsubscribeFunction) { return unsubscribeFunction(); }); }; }; var resetState = function resetState(newVersion) { resetSubject.next(null); unsubscribeFromCandidates(); unsubscribeFromDataChannels(); unsubscribeFromPeerConnection(); reliableDataChannel.close(); unreliableDataChannel.close(); peerConnection.close(); if (send !== null) { observer.next([clientId, true]); } isFresh = true; numberOfAppliedCandidates = 0; numberOfExpectedCandidates = version === newVersion ? numberOfExpectedCandidates : Infinity; numberOfGatheredCandidates = 0; peerConnection = createPeerConnection(); receivedCandidates.length = version === newVersion ? receivedCandidates.length : 0; reliableDataChannel = peerConnection.createDataChannel('', { id: 0, negotiated: true, ordered: true }); send = null; unreliableDataChannel = peerConnection.createDataChannel('', { id: 1, maxRetransmits: 0, negotiated: true, ordered: false }); unsubscribeFromCandidates = subscribeToCandidates(); unsubscribeFromDataChannels = subscribeToDataChannels(); unsubscribeFromPeerConnection = subscribeToPeerConnection(); version = newVersion; }; var isFresh = true; var numberOfAppliedCandidates = 0; var numberOfExpectedCandidates = Infinity; var numberOfGatheredCandidates = 0; var peerConnection = createPeerConnection(); var reliableDataChannel = peerConnection.createDataChannel('', { id: 0, negotiated: true, ordered: true }); var send = null; var unrecoverableError = null; var unreliableDataChannel = peerConnection.createDataChannel('', { id: 1, maxRetransmits: 0, negotiated: true, ordered: false }); var unsubscribeFromCandidates = subscribeToCandidates(); var unsubscribeFromDataChannels = subscribeToDataChannels(); var unsubscribeFromPeerConnection = subscribeToPeerConnection(); var version = 0; var addFinalCandidate = /*#__PURE__*/function () { var _ref8 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(numberOfNewlyAppliedCandidates) { return _regeneratorRuntime.wrap(function (_context) { while (1) switch (_context.prev = _context.next) { case 0: numberOfAppliedCandidates += numberOfNewlyAppliedCandidates; if (!(numberOfAppliedCandidates === numberOfExpectedCandidates)) { _context.next = 1; break; } _context.next = 1; return peerConnection.addIceCandidate(); case 1: case "end": return _context.stop(); } }, _callee); })); return function addFinalCandidate(_x) { return _ref8.apply(this, arguments); }; }(); var jsonifyDescription = function jsonifyDescription(description) { return description instanceof RTCSessionDescription ? description.toJSON() : description; }; var processEvent = function processEvent(event) { var type = event.type; if (type === 'answer' && isActive) { if (version > event.version) { return rxjs.EMPTY; } if (version === event.version && !isFresh) { return ignoreLateResult(peerConnection.setRemoteDescription(event)).pipe(rxjs.mergeMap(function () { return rxjs.from(receivedCandidates); }), rxjs.mergeMap(function (receivedCandidate) { return ignoreLateResult(peerConnection.addIceCandidate(receivedCandidate)); }), rxjs.count(), rxjs.mergeMap(function (numberOfNewlyAppliedCandidates) { return ignoreLateResult(addFinalCandidate(numberOfNewlyAppliedCandidates)); })); } } if (type === 'candidate') { if (version > event.version) { return rxjs.EMPTY; } if (version < event.version && !isActive) { resetState(event.version); } if (version === event.version) { if (peerConnection.remoteDescription === null) { receivedCandidates.push(event); return rxjs.EMPTY; } return ignoreLateResult(peerConnection.addIceCandidate(event)).pipe(rxjs.mergeMap(function () { return ignoreLateResult(addFinalCandidate(1)); })); } } if (type === 'error' && isActive) { if (version > event.version) { return rxjs.EMPTY; } resetState(event.version + 1); return createAndSendOffer(); } if (type === 'notice' && !isActive) { return rxjs.EMPTY; } if (type === 'offer' && !isActive) { if (version > event.version) { return rxjs.EMPTY; } if (version < event.version) { resetState(event.version); } isFresh = false; return ignoreLateResult(peerConnection.setRemoteDescription(event)).pipe(rxjs.mergeMap(function () { return rxjs.merge(ignoreLateResult(peerConnection.setLocalDescription()).pipe(rxjs.tap(function () { var _peerConnection2 = peerConnection, localDescription = _peerConnection2.localDescription; if (localDescription === null) { throw new Error('The local description is not set.'); } sendSignalingEvent(_objectSpread$2(_objectSpread$2({}, jsonifyDescription(localDescription)), {}, { client: { id: clientId }, version: version })); })), rxjs.from(receivedCandidates).pipe(rxjs.mergeMap(function (receivedCandidate) { return ignoreLateResult(peerConnection.addIceCandidate(receivedCandidate)); }), rxjs.count(), rxjs.mergeMap(function (numberOfNewlyAppliedCandidates) { return ignoreLateResult(addFinalCandidate(numberOfNewlyAppliedCandidates)); }))); })); } if (type === 'request' && isActive) { if (version === 0 && isFresh) { return createAndSendOffer(); } return rxjs.EMPTY; } if (type === 'summary') { if (version > event.version) { return rxjs.EMPTY; } if (version < event.version && !isActive) { resetState(event.version); } if (version === event.version) { numberOfExpectedCandidates = event.numberOfGatheredCandidates; return ignoreLateResult(addFinalCandidate(0)); } } unrecoverableError = new Error("The current event of type \"".concat(type, "\" can't be processed.")); // tslint:disable-next-line:rxjs-throw-error return rxjs.throwError(function () { return unrecoverableError; }); }; observer.next([clientId, true]); return rxjs.merge(rxjs.defer(function () { return rxjs.from(errorEvents); }), // tslint:disable-next-line:rxjs-throw-error errorSubject.pipe(rxjs.mergeMap(function (err) { return rxjs.throwError(function () { return err; }); })), observable.pipe(echo(function () { return sendSignalingEvent({ client: { id: clientId }, type: 'check' }); }, function () { return reliableDataChannel.readyState !== 'open' || unreliableDataChannel.readyState !== 'open'; }, rxjs.interval(5000)), operators.inexorably(function (notification) { if (notification !== undefined) { errorSubject.complete(); } }))).pipe(rxjs.mergeMap(function (event) { return processEvent(event).pipe(rxjs.takeUntil(resetSubject)); }), rxjs.retry({ delay: function delay(err) { if (err === unrecoverableError) { // tslint:disable-next-line:rxjs-throw-error return rxjs.throwError(function () { return err; }); } errorEvents.length = 0; if (isFresh) { resetState(version); } else { var errorEvent = { client: { id: clientId }, message: err.message, name: err.name, type: 'error', version: version }; if (isActive) { errorEvents.push(errorEvent); } else { resetState(version + 1); sendSignalingEvent(errorEvent); } } return rxjs.of(null); } }), rxjs.takeUntil(rxjs.concat(observable.pipe(rxjs.ignoreElements()), rxjs.of(null))), rxjs.finalize(function () { unsubscribeFromCandidates(); unsubscribeFromDataChannels(); unsubscribeFromPeerConnection(); reliableDataChannel.close(); unreliableDataChannel.close(); peerConnection.close(); })).subscribe({ complete: function complete() { observer.next([clientId, false]); observer.complete(); }, error: function error(err) { return observer.error(err); } }); }); })); }; }; var retryBackoff = function retryBackoff() { return function (source) { return rxjs.defer(function () { var attempts = 4; var interval = 1000; var index = 0; return source.pipe(rxjs.retry({ delay: function delay(error) { index += 1; return rxjs.iif(function () { return index < attempts; }, rxjs.timer(interval * Math.pow(index, 2)), rxjs.throwError(function () { return error; }) // tslint:disable-line:rxjs-throw-error ); } }), rxjs.tap(function () { return index = 0; })); }); }; }; var selectMostLikelyOffset = function selectMostLikelyOffset() { return function (source) { return source.pipe(rxjs.scan(function (tuples, tuple) { return [].concat(_toConsumableArray(tuples.slice(-59)), [tuple]); }, []), rxjs.map(function (tuples) { return tuples.slice(1).reduce(function (tupleWithSmallestRoundTripTime, tuple) { return tupleWithSmallestRoundTripTime[1] < tuple[1] ? tupleWithSmallestRoundTripTime : tuple; }, tuples[0]); })); }; }; var sendPeriodicPings = function sendPeriodicPings(localSentTimesSubject, now) { return function (source) { return source.pipe(rxjs.map(function (_ref) { var _ref2 = _slicedToArray(_ref, 2), send = _ref2[1]; return rxjs.interval(1000).pipe(rxjs.startWith(0), rxjs.map(function (_, index) { send({ index: index, type: 'ping' }); return now(); }), rxjs.withLatestFrom(localSentTimesSubject), rxjs.tap(function (_ref3) { var _ref4 = _slicedToArray(_ref3, 2), localSentTime = _ref4[0], _ref4$ = _slicedToArray(_ref4[1], 2), startIndex = _ref4$[0], localSentTimes = _ref4$[1]; return localSentTimesSubject.next([startIndex, [].concat(_toConsumableArray(localSentTimes), [localSentTime])]); }), rxjs.ignoreElements()); }), rxjs.endWith(rxjs.EMPTY), rxjs.switchAll()); }; }; var takeUntilFatalValue = function takeUntilFatalValue(isFatalValue, handleFatalValue) { return rxjs.connect(function (values$) { var _partition = rxjs.partition(values$, isFatalValue), _partition2 = _slicedToArray(_partition, 2), fatalEvent$ = _partition2[0], otherEvent$ = _partition2[1]; return otherEvent$.pipe(rxjs.takeUntil(fatalEvent$.pipe(rxjs.tap(handleFatalValue)))); }); }; var _excluded = ["hops", "version"]; function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: true } : { done: false, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = true, u = false; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = true, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$1(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$1(r, a) : void 0; } } function _arrayLikeToArray$1(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function ownKeys$1(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$1(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$1(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } var SUENC_URL = 'wss://matchmaker.suenc.io'; var PROVIDER_ID_REGEX = /^[\dA-Za-z]{20}$/; var createTimingProviderConstructor = function createTimingProviderConstructor(createRTCPeerConnection, createSignaling, eventTargetConstructor, performance, setTimeout, sortByHopsAndRoundTripTime, updateTimingStateVector) { return /*#__PURE__*/function (_eventTargetConstruct) { function TimingProvider(providerIdOrUrl) { var _this; _classCallCheck(this, TimingProvider); _this = _callSuper(this, TimingProvider); var timestamp = performance.now() / 1000; _this._clientId = ''; _this._endPosition = Number.POSITIVE_INFINITY; _this._error = null; _this._hops = []; _this._onadjust = null; _this._onchange = null; _this._onreadystatechange = null; _this._origin = Number.MAX_SAFE_INTEGER; _this._providerIdOrUrl = providerIdOrUrl; _this._readyState = 'connecting'; _this._skew = 0; _this._startPosition = Number.NEGATIVE_INFINITY; _this._subscription = null; _this._updateRequestsSubject = new rxjs.Subject(); _this._vector = { acceleration: 0, position: 0, timestamp: timestamp, velocity: 0 }; _this._version = 0; _this._createClient(); return _this; } _inherits(TimingProvider, _eventTargetConstruct); return _createClass(TimingProvider, [{ key: "endPosition", get: function get() { return this._endPosition; } }, { key: "error", get: function get() { return this._error; } }, { key: "onadjust", get: function get() { return this._onadjust === null ? this._onadjust : this._onadjust[0]; }, set: function set(value) { if (this._onadjust !== null) { this.removeEventListener('adjust', this._onadjust[1]); } if (typeof value === 'function') { var boundListener = value.bind(this); this.addEventListener('adjust', boundListener); this._onadjust = [value, boundListener]; } else { this._onadjust = null; } } }, { key: "onchange", get: function get() { return this._onchange === null ? this._onchange : this._onchange[0]; }, set: function set(value) { if (this._onchange !== null) { this.removeEventListener('change', this._onchange[1]); } if (typeof value === 'function') { var boundListener = value.bind(this); this.addEventListener('change', boundListener); this._onchange = [value, boundListener]; } else { this._onchange = null; } } }, { key: "onreadystatechange", get: function get() { return this._onreadystatechange === null ? this._onreadystatechange : this._onreadystatechange[0]; }, set: function set(value) { if (this._onreadystatechange !== null) { this.removeEventListener('readystatechange', this._onreadystatechange[1]); } if (typeof value === 'function') { var boundListener = value.bind(this); this.addEventListener('readystatechange', boundListener); this._onreadystatechange = [value, boundListener]; } else { this._onreadystatechange = null; } } }, { key: "readyState", get: function get() { return this._readyState; } }, { key: "skew", get: function get() { return this._skew; } }, { key: "startPosition", get: function get() { return this._startPosition; } }, { key: "vector", get: function get() { return this._vector; } }, { key: "destroy", value: function destroy() { var _this2 = this; if (this._subscription === null) { throw new Error('The timingProvider is already destroyed.'); } this._readyState = 'closed'; this._subscription.unsubscribe(); this._subscription = null; this._updateRequestsSubject.complete(); setTimeout(function () { return _this2.dispatchEvent(new Event('readystatechange')); }); } }, { key: "update", value: function update(newVector) { if (this._subscription === null) { return Promise.reject(new Error("The timingProvider is destroyed and can't be updated.")); } var updatedVector = updateTimingStateVector(this._vector, newVector); if (updatedVector !== null) { this._updateRequestsSubject.next([_objectSpread$1(_objectSpread$1({}, updatedVector), {}, { hops: [], version: this._version + 1 }), null]); } return Promise.resolve(); } }, { key: "_createClient", value: function _createClient() { var _this3 = this; var url = PROVIDER_ID_REGEX.test(this._providerIdOrUrl) ? "".concat(SUENC_URL, "?providerId=").concat(this._providerIdOrUrl) : this._providerIdOrUrl; this._subscription = rxjs.merge(rxjs.concat(rxjs.from(subscribableThings.online()).pipe(operators.equals(true), rxjs.first(), rxjs.ignoreElements()), rxjs.defer(function () { var _createSignaling = createSignaling(url), _createSignaling2 = _slicedToArray(_createSignaling, 2), signalingEvent$ = _createSignaling2[0], sendSignalingEvent = _createSignaling2[1]; return signalingEvent$.pipe(takeUntilFatalValue(function (event) { return event.type === 'closure'; }, function () { var err = new Error('Your plan has exceeded its quota.'); _this3._error = err; _this3._readyState = 'closed'; _this3.dispatchEvent(new Event('readystatechange')); }), enforceOrder(function (event) { return event.type === 'init'; }), rxjs.concatMap(function (event) { if (event.type === 'array') { return rxjs.from(event.events); } if (event.type === 'init') { var clientId = event.client.id, events = event.events, origin = event.origin; _this3._clientId = clientId; _this3._origin = origin; if (events.length === 0 && _this3._readyState === 'connecting') { _this3._readyState = 'open'; _this3.dispatchEvent(new Event('readystatechange')); } return rxjs.from(events); } return rxjs.of(event); }), demultiplexMessages(function () { return _this3._clientId; }, rxjs.timer(10000)), negotiateDataChannels(createRTCPeerConnection, sendSignalingEvent)); })).pipe(retryBackoff(), rxjs.catchError(function (err) { _this3._error = err; _this3._readyState = 'closed'; _this3.dispatchEvent(new Event('readystatechange')); return rxjs.EMPTY; }), rxjs.tap(function (dataChannelTuple) { if (isSendPeerToPeerMessageTuple(dataChannelTuple) && _this3._readyState === 'connecting') { _this3._readyState = 'open'; _this3.dispatchEvent(new Event('readystatechange')); } }), rxjs.scan(function (_ref, dataChannelTuple) { var _ref2 = _slicedToArray(_ref, 2), dataChannelTuples = _ref2[1]; var index = dataChannelTuples.findIndex(function (_ref3) { var _ref4 = _slicedToArray(_ref3, 1), clientId = _ref4[0]; return clientId === dataChannelTuple[0]; }); if (index === -1) { if (isTrueTuple(dataChannelTuple) || isSendPeerToPeerMessageTuple(dataChannelTuple)) { dataChannelTuples.push(dataChannelTuple); } } else if (isFalseTuple(dataChannelTuple)) { dataChannelTuples.splice(index, 1); } else if (isTrueTuple(dataChannelTuple) || isSendPeerToPeerMessageTuple(dataChannelTuple)) { dataChannelTuples[index] = dataChannelTuple; } return [dataChannelTuple, dataChannelTuples]; }, [, []] // tslint:disable-line:no