twilio-video
Version:
Twilio Video JavaScript Library
433 lines • 17.9 kB
JavaScript
;
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var guessBrowser = require('../webrtc/util').guessBrowser;
var IceReportFactory = require('./icereportfactory');
var PeerConnectionReport = require('./peerconnectionreport');
var ReceiverReportFactory = require('./receiverreportfactory');
var SenderReportFactory = require('./senderreportfactory');
/**
* @typedef {string} TrackId
*/
/**
* @typedef {string} StatsId
*/
/**
* @interface SenderReportFactoriesByMediaType
* @property {Map<StatsId, SenderReportFactory>} audio
* @property {Map<StatsId, SenderReportFactory>} video
*/
/**
* @interface ReceiverReportFactoriesByMediaType
* @property {Map<StatsId, ReceiverReportFactory>} audio
* @property {Map<StatsId, ReceiverReportFactory>} video
*/
/**
* @interface SenderAndReceiverReportFactories
* @property {Map<StatsId, SenderReportFactories>} send
* @property {Map<StatsId, ReceiverReportFactories>} recv
*/
/**
* @interface {StatsIdsByMediaType}
* @property {Set<StatsId>} audio
* @property {Set<StatsId>} video
*/
/**
* @property {RTCPeerConnection} pc
* @property {IceReportFactory} iceReportFactory
* @property {SenderAndReceiverReportFactories} audio
* @property {SenderAndReceiverReportFactories} video
* @property {?PeerConnectionReport} lastReport
*/
var PeerConnectionReportFactory = /** @class */ (function () {
/**
* Construct a {@link PeerConnectionReportFactory}.
* @param {RTCPeerConnection} pc
*/
function PeerConnectionReportFactory(pc) {
Object.defineProperties(this, {
pc: {
enumerable: true,
value: pc
},
ice: {
enumerable: true,
value: new IceReportFactory()
},
audio: {
enumerable: true,
value: {
send: new Map(),
recv: new Map()
}
},
video: {
enumerable: true,
value: {
send: new Map(),
recv: new Map()
}
},
lastReport: {
enumerable: true,
value: null,
writable: true
}
});
}
/**
* Create a {@link PeerConnectionReport}.
* @returns {Promise<PeerConnectionReport>}
*/
PeerConnectionReportFactory.prototype.next = function () {
var _this = this;
var updatePromise = guessBrowser() === 'firefox'
? updateFirefox(this)
: updateChrome(this);
return updatePromise.then(function () {
var audioSenderReportFactories = __spreadArray([], __read(_this.audio.send.values()), false);
var videoSenderReportFactories = __spreadArray([], __read(_this.video.send.values()), false);
var audioReceiverReportFactories = __spreadArray([], __read(_this.audio.recv.values()), false);
var videoReceiverReportFactories = __spreadArray([], __read(_this.video.recv.values()), false);
var report = new PeerConnectionReport(_this.ice.lastReport, {
send: audioSenderReportFactories.map(function (factory) { return factory.lastReport; }).filter(function (report) { return report; }),
recv: audioReceiverReportFactories.map(function (factory) { return factory.lastReport; }).filter(function (report) { return report; })
}, {
send: videoSenderReportFactories.map(function (factory) { return factory.lastReport; }).filter(function (report) { return report; }),
recv: videoReceiverReportFactories.map(function (factory) { return factory.lastReport; }).filter(function (report) { return report; })
});
_this.lastReport = report;
return report;
});
};
return PeerConnectionReportFactory;
}());
/**
* Construct a Map from MediaStreamTrack Ids to RTCStatsReports.
* @param {Array<RTCRtpSender>|Array<RTCRtpReceiver>} sendersOrReceivers - each
* RTCRtpSender should have a non-null track
* @returns {Promise<Map<TrackId, RTCStats>>}
*/
function getSenderOrReceiverReports(sendersOrReceivers) {
return Promise.all(sendersOrReceivers.map(function (senderOrReceiver) {
var trackId = senderOrReceiver.track.id;
return senderOrReceiver.getStats().then(function (report) {
var e_1, _a;
try {
// NOTE(mroberts): We have to rewrite Ids due to this bug:
//
// https://bugzilla.mozilla.org/show_bug.cgi?id=1463430
//
for (var _b = __values(report.values()), _c = _b.next(); !_c.done; _c = _b.next()) {
var stats = _c.value;
if (stats.type === 'inbound-rtp') {
stats.id = "".concat(trackId, "-").concat(stats.id);
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
return [trackId, report];
});
})).then(function (pairs) { return new Map(pairs); });
}
/**
* @param {SenderReportFactory.constructor} SenderReportFactory
* @param {SenderReportFactoriesByMediaType} sendersByMediaType
* @param {RTCStatsReport} report
* @param {RTCStats} stats
* @param {TrackId} [trackId]
* @returns {?SenderReportFactory}
*/ /**
* @param {ReceiverReportFactory.constructor} ReceiverReportFactory
* @param {ReceiverReportFactoriesByMediaType} receiversByMediaType
* @param {RTCStatsReport} report
* @param {RTCStats} stats
* @param {TrackId} [trackId]
* @returns {?ReceiverReportFactory}
*/
function getOrCreateSenderOrReceiverReportFactory(SenderOrReceiverReportFactory, sendersOrReceiversByMediaType, report, stats, trackId) {
var sendersOrReceivers = sendersOrReceiversByMediaType[stats.mediaType];
if (!trackId) {
var trackStats = report.get(stats.trackId);
if (trackStats) {
trackId = trackStats.trackIdentifier;
}
}
if (sendersOrReceivers && trackId) {
if (sendersOrReceivers.has(stats.id)) {
return sendersOrReceivers.get(stats.id);
}
var senderOrReceiverFactory = new SenderOrReceiverReportFactory(trackId, stats);
sendersOrReceivers.set(stats.id, senderOrReceiverFactory);
}
return null;
}
/**
* @param {PeerConnectionReportFactory} factory
* @returns {SenderReportFactoriesByMediaType}
*/
function getSenderReportFactoriesByMediaType(factory) {
return { audio: factory.audio.send, video: factory.video.send };
}
/**
* @param {PeerConnectionReportFactory} factory
* @returns {ReceiverReportFactoriesByMediaType}
*/
function getReceiverReportFactoriesByMediaType(factory) {
return { audio: factory.audio.recv, video: factory.video.recv };
}
/**
* @param {PeerConnectionReportFactory} factory
* @param {RTCStatsReport} report
* @param {RTCStats} stats
* @param {TrackId} [trackId]
* @returns {?SenderReportFactory}
*/
function getOrCreateSenderReportFactory(factory, report, stats, trackId) {
return getOrCreateSenderOrReceiverReportFactory(SenderReportFactory, getSenderReportFactoriesByMediaType(factory), report, stats, trackId);
}
/**
* @param {PeerConnectionReportFactory} factory
* @param {RTCStatsReport} report
* @param {RTCStats} stats
* @param {TrackId} [trackId]
* @returns {?ReceiverReportFactory}
*/
function getOrCreateReceiverReportFactory(factory, report, stats, trackId) {
return getOrCreateSenderOrReceiverReportFactory(ReceiverReportFactory, getReceiverReportFactoriesByMediaType(factory), report, stats, trackId);
}
/**
* @param {PeerConnectionReportFactory} factory
* @retuns {StatsIdsByMediaType}
*/
function getSenderReportFactoryIdsByMediaType(factory) {
return {
audio: new Set(factory.audio.send.keys()),
video: new Set(factory.video.send.keys())
};
}
/**
* @param {PeerConnectionReportFactory} factory
* @retuns {StatsIdsByMediaType}
*/
function getReceiverReportFactoryIdsByMediaType(factory) {
return {
audio: new Set(factory.audio.recv.keys()),
video: new Set(factory.video.recv.keys())
};
}
/**
* @param {PeerConnectionReportFactory} factory
* @param {RTCStatsReport} report
* @param {StatsIdsByMediaType} senderReportFactoryIdsToDeleteByMediaType
* @param {TrackId} [trackId]
* @returns {void}
*/
function updateSenderReports(factory, report, senderReportFactoryIdsToDeleteByMediaType, trackId) {
var e_2, _a;
try {
for (var _b = __values(report.values()), _c = _b.next(); !_c.done; _c = _b.next()) {
var stats = _c.value;
if (stats.type === 'outbound-rtp' && !stats.isRemote) {
if (guessBrowser() !== 'firefox' && !stats.trackId) {
continue;
}
var senderReportFactoryIdsToDelete = senderReportFactoryIdsToDeleteByMediaType[stats.mediaType];
if (senderReportFactoryIdsToDelete) {
senderReportFactoryIdsToDelete.delete(stats.id);
}
var senderReportFactory = getOrCreateSenderReportFactory(factory, report, stats, trackId);
if (senderReportFactory) {
var remoteInboundStats = report.get(stats.remoteId);
senderReportFactory.next(trackId || senderReportFactory.trackId, stats, remoteInboundStats);
}
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_2) throw e_2.error; }
}
}
/**
* @param {PeerConnectionReportFactory} factory
* @param {RTCStatsReport} report
* @param {StatsIdsByMediaType} receiverReportFactoryIdsToDeleteByMediaType
* @param {TrackId} [trackId]
* @returns {void}
*/
function updateReceiverReports(factory, report, receiverReportFactoryIdsToDeleteByMediaType, trackId) {
var e_3, _a;
try {
for (var _b = __values(report.values()), _c = _b.next(); !_c.done; _c = _b.next()) {
var stats = _c.value;
if (stats.type === 'inbound-rtp' && !stats.isRemote) {
var receiverReportFactoryIdsToDelete = receiverReportFactoryIdsToDeleteByMediaType[stats.mediaType];
if (receiverReportFactoryIdsToDelete) {
receiverReportFactoryIdsToDelete.delete(stats.id);
}
var receiverReportFactory = getOrCreateReceiverReportFactory(factory, report, stats, trackId);
if (receiverReportFactory) {
receiverReportFactory.next(trackId || receiverReportFactory.trackId, stats);
}
}
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_3) throw e_3.error; }
}
}
/**
* @param {SenderReportFactoriesByMediaType|ReceiverReportFactoriesByMediaType} senderOrReceiverReportFactoriesByMediaType
* @param {StatsIdsByMediaType} senderOrReceiverReportFactoryIdsByMediaType
* @returns {void}
*/
function deleteSenderOrReceiverReportFactories(senderOrReceiverReportFactoriesByMediaType, senderOrReceiverReportFactoryIdsByMediaType) {
var _loop_1 = function (mediaType) {
var senderOrReceiverReportFactories = senderOrReceiverReportFactoriesByMediaType[mediaType];
var senderOrReceiverReportFactoryIds = senderOrReceiverReportFactoryIdsByMediaType[mediaType];
senderOrReceiverReportFactoryIds.forEach(function (senderOrReceiverReportFactoryId) { return senderOrReceiverReportFactories.delete(senderOrReceiverReportFactoryId); });
};
for (var mediaType in senderOrReceiverReportFactoryIdsByMediaType) {
_loop_1(mediaType);
}
}
/**
* @param {IceReportFactory} ice
* @param {RTCStatsReport} report
* @returns {void}
*/
function updateIceReport(ice, report) {
var e_4, _a, e_5, _b;
var selectedCandidatePair;
try {
for (var _c = __values(report.values()), _d = _c.next(); !_d.done; _d = _c.next()) {
var stats = _d.value;
if (stats.type === 'transport') {
selectedCandidatePair = report.get(stats.selectedCandidatePairId);
}
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
}
finally { if (e_4) throw e_4.error; }
}
if (selectedCandidatePair) {
ice.next(selectedCandidatePair);
return;
}
try {
for (var _e = __values(report.values()), _f = _e.next(); !_f.done; _f = _e.next()) {
var stats = _f.value;
if (stats.type === 'candidate-pair'
&& stats.nominated
&& ('selected' in stats ? stats.selected : true)) {
ice.next(stats);
}
}
}
catch (e_5_1) { e_5 = { error: e_5_1 }; }
finally {
try {
if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
}
finally { if (e_5) throw e_5.error; }
}
}
/**
* @param {PeerConnectionReportFactory} factory
* @returns {Promise<PeerConnectionReport>}
*/
function updateFirefox(factory) {
var senders = factory.pc.getTransceivers()
.filter(function (transceiver) { return transceiver.currentDirection && transceiver.currentDirection.match(/send/) && transceiver.sender.track; })
.map(function (transceiver) { return transceiver.sender; });
var receivers = factory.pc.getTransceivers()
.filter(function (transceiver) { return transceiver.currentDirection && transceiver.currentDirection.match(/recv/); })
.map(function (transceiver) { return transceiver.receiver; });
return Promise.all([
getSenderOrReceiverReports(senders),
getSenderOrReceiverReports(receivers),
factory.pc.getStats()
]).then(function (_a) {
var _b = __read(_a, 3), senderReports = _b[0], receiverReports = _b[1], pcReport = _b[2];
var senderReportFactoriesByMediaType = getSenderReportFactoriesByMediaType(factory);
var senderReportFactoryIdsToDeleteByMediaType = getSenderReportFactoryIdsByMediaType(factory);
senderReports.forEach(function (report, trackId) { return updateSenderReports(factory, report, senderReportFactoryIdsToDeleteByMediaType, trackId); });
deleteSenderOrReceiverReportFactories(senderReportFactoriesByMediaType, senderReportFactoryIdsToDeleteByMediaType);
var receiverReportFactoriesByMediaType = getReceiverReportFactoriesByMediaType(factory);
var receiverReportFactoryIdsToDeleteByMediaType = getReceiverReportFactoryIdsByMediaType(factory);
receiverReports.forEach(function (report, trackId) { return updateReceiverReports(factory, report, receiverReportFactoryIdsToDeleteByMediaType, trackId); });
deleteSenderOrReceiverReportFactories(receiverReportFactoriesByMediaType, receiverReportFactoryIdsToDeleteByMediaType);
updateIceReport(factory.ice, pcReport);
});
}
/**
* @param {PeerConnectionReportFactory} factory
* @returns {Promise<PeerConnectionReport>}
*/
function updateChrome(factory) {
return factory.pc.getStats().then(function (report) {
var senderReportFactoriesByMediaType = getSenderReportFactoriesByMediaType(factory);
var senderReportFactoryIdsToDeleteByMediaType = getSenderReportFactoryIdsByMediaType(factory);
updateSenderReports(factory, report, senderReportFactoryIdsToDeleteByMediaType);
deleteSenderOrReceiverReportFactories(senderReportFactoriesByMediaType, senderReportFactoryIdsToDeleteByMediaType);
var receiverReportFactoriesByMediaType = getReceiverReportFactoriesByMediaType(factory);
var receiverReportFactoryIdsToDeleteByMediaType = getReceiverReportFactoryIdsByMediaType(factory);
updateReceiverReports(factory, report, receiverReportFactoryIdsToDeleteByMediaType);
deleteSenderOrReceiverReportFactories(receiverReportFactoriesByMediaType, receiverReportFactoryIdsToDeleteByMediaType);
updateIceReport(factory.ice, report);
});
}
module.exports = PeerConnectionReportFactory;
//# sourceMappingURL=peerconnectionreportfactory.js.map