timing-provider
Version:
An implementation of the timing provider specification.
1,044 lines (1,016 loc) • 69.2 kB
JavaScript
(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