@messagebird/client
Advanced tools
Comparing version 1.0.0-next-rc.4 to 1.0.0-next-rc.5
@@ -0,1 +1,13 @@ | ||
# [1.0.0-next-rc.4](https://git.messagebird.io/frontend/javascript-webrtc-sdk/compare/v1.0.0-next-rc.3...v1.0.0-next-rc.4) (2020-04-29) | ||
### Bug Fixes | ||
* registration event firing twice ([46a5d32](https://git.messagebird.io/frontend/javascript-webrtc-sdk/commit/46a5d32f1a8c6033fcf03d9786ae5bc7d70f68bf)) | ||
### Features | ||
* prevent unlimited reconnection retries ([35e61de](https://git.messagebird.io/frontend/javascript-webrtc-sdk/commit/35e61de5b7374d28fe4f8f450cbd9fe50c044c65)) | ||
# [1.0.0-next-rc.3](https://git.messagebird.io/frontend/javascript-webrtc-sdk/compare/v1.0.0-next-rc.2...v1.0.0-next-rc.3) (2020-04-24) | ||
@@ -2,0 +14,0 @@ |
@@ -81,3 +81,3 @@ 'use strict'; | ||
function getSDKVersionHeader() { | ||
var version = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "1078f707" ; | ||
var version = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "b1598330" ; | ||
return "SDK-Version: ".concat(version); | ||
@@ -565,5 +565,144 @@ } | ||
var reports = []; | ||
var StatsReport = /*#__PURE__*/function () { | ||
function StatsReport(report, priorReport) { | ||
var _this = this; | ||
_classCallCheck(this, StatsReport); | ||
_defineProperty(this, "priorReport", void 0); | ||
_defineProperty(this, "_transport", void 0); | ||
_defineProperty(this, "_remoteCandidate", void 0); | ||
_defineProperty(this, "_localCandidate", void 0); | ||
_defineProperty(this, "_codecs", []); | ||
_defineProperty(this, "_candidatePair", void 0); | ||
_defineProperty(this, "_peerConnection", void 0); | ||
_defineProperty(this, "_remoteInboundRTP", {}); | ||
_defineProperty(this, "_remoteOutboundRTP", {}); | ||
_defineProperty(this, "_outboundRTP", {}); | ||
_defineProperty(this, "_inboundRTP", {}); | ||
_defineProperty(this, "_remoteTracks", {}); | ||
_defineProperty(this, "_localTracks", {}); | ||
this.priorReport = this.trimPriorReport(priorReport); | ||
report === null || report === void 0 ? void 0 : report.forEach(function (stat) { | ||
switch (stat.type) { | ||
case RTCStatsTypes.Transport: | ||
_this.transport = stat; | ||
break; | ||
case RTCStatsTypes.RemoteCandidate: | ||
_this.remoteCandidate = stat; | ||
break; | ||
case RTCStatsTypes.LocalCandidate: | ||
_this.localCandidate = stat; | ||
break; | ||
case RTCStatsTypes.RemoteInboundRTP: | ||
_this.remoteInboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.Codec: | ||
_this.codecs = stat; | ||
break; | ||
case RTCStatsTypes.RemoteOutboundRTP: | ||
_this.remoteOutboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.CandidatePair: | ||
_this.candidatePair = stat; | ||
break; | ||
case RTCStatsTypes.PeerConnection: | ||
_this.peerConnection = stat; | ||
break; | ||
case RTCStatsTypes.OutboundRTP: | ||
_this.outboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.InboundRTP: | ||
_this.inboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.Track: | ||
stat.remoteSource ? _this.remoteTracks = stat : _this.localTracks = stat; | ||
break; | ||
} | ||
}); | ||
this._codecs = this._codecs.filter(function (codec) { | ||
return codec.id === _this._inboundRTP.audio.codecId || codec.id === _this._outboundRTP.audio.codecId || codec.payloadType === 126; | ||
}); | ||
} | ||
_createClass(StatsReport, [{ | ||
key: "trimPriorReport", | ||
value: function trimPriorReport(priorReport) { | ||
var _priorReport$priorRep; | ||
if (priorReport === undefined) { | ||
return priorReport; | ||
} // The stats reports object contains a "priorReport" which | ||
// Then contains another object with the key "priorReport". | ||
// We don't want to end up with an infinite stream of prior reports | ||
// So we remove the prior report after 2 levels of nesting. | ||
if ((_priorReport$priorRep = priorReport.priorReport) === null || _priorReport$priorRep === void 0 ? void 0 : _priorReport$priorRep.priorReport) { | ||
delete priorReport.priorReport.priorReport; | ||
} | ||
return priorReport; | ||
} | ||
}, { | ||
key: "mos", | ||
value: function mos() { | ||
var _this$priorReport, _this$priorReport$_re; | ||
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'audio'; | ||
if (!((_this$priorReport = this.priorReport) === null || _this$priorReport === void 0 ? void 0 : (_this$priorReport$_re = _this$priorReport._remoteInboundRTP) === null || _this$priorReport$_re === void 0 ? void 0 : _this$priorReport$_re[type])) return null; // Parse variables for the current RTP Data | ||
var _this$_remoteInboundR = this._remoteInboundRTP[type], | ||
currentRTT = _this$_remoteInboundR.roundTripTime, | ||
currentJitter = _this$_remoteInboundR.jitter, | ||
currentPacketsLost = _this$_remoteInboundR.packetsLost; // Parse relevant data from the last RTP Data | ||
var _this$priorReport$_re2 = this.priorReport._remoteInboundRTP[type], | ||
priorRTT = _this$priorReport$_re2.roundTripTime, | ||
priorPacketsLost = _this$priorReport$_re2.packetsLost; // Average the RTT from the previous report and this report | ||
var avgLatency = (currentRTT + priorRTT) / 2; // Determine number of packets lost between reports | ||
var totalPacketsLost = currentPacketsLost - priorPacketsLost; // Calculate the latency | ||
var latency = avgLatency + currentJitter + totalPacketsLost; // TODO: Provide a more accurate R value which factors | ||
// in the audio codec that is being used. | ||
var r = 93.25 - (latency - 120) / 10; | ||
if (latency < 160) { | ||
r = 93.25 - latency / 40; | ||
} | ||
r -= totalPacketsLost * 2.5; | ||
r = Math.max(r, 0); // Final MOS Score calculation is an approximate | ||
// based on ITU-T G.107, Annex B Recommendation. | ||
var finalR = 1 + 0.035 * r + 0.000007 * r * (r - 60) * (100 - r); | ||
return +finalR.toFixed(1); | ||
} | ||
}, { | ||
key: "transport", | ||
@@ -737,150 +876,103 @@ set: function set(stat) { | ||
} | ||
}]); | ||
}, { | ||
key: "data", | ||
get: function get() { | ||
var _this$priorReport2, _this$priorReport2$_r; | ||
function StatsReport(report) { | ||
var _this = this; | ||
var stats = [this._transport, this._candidatePair, this._remoteCandidate, this._localCandidate, this._peerConnection].concat(_toConsumableArray(this._codecs), _toConsumableArray(Object.values(this._remoteInboundRTP)), _toConsumableArray(Object.values(this._remoteOutboundRTP)), _toConsumableArray(Object.values(this._outboundRTP)), _toConsumableArray(Object.values(this._inboundRTP)), _toConsumableArray(Object.values(this._remoteTracks)), _toConsumableArray(Object.values(this._localTracks))); | ||
_classCallCheck(this, StatsReport); | ||
if ((_this$priorReport2 = this.priorReport) === null || _this$priorReport2 === void 0 ? void 0 : (_this$priorReport2$_r = _this$priorReport2._remoteInboundRTP) === null || _this$priorReport2$_r === void 0 ? void 0 : _this$priorReport2$_r.audio) { | ||
stats.push({ | ||
mos: this.mos() | ||
}); | ||
} | ||
_defineProperty(this, "priorReport", void 0); | ||
_defineProperty(this, "_transport", void 0); | ||
_defineProperty(this, "_remoteCandidate", void 0); | ||
_defineProperty(this, "_localCandidate", void 0); | ||
_defineProperty(this, "_codecs", []); | ||
_defineProperty(this, "_candidatePair", void 0); | ||
_defineProperty(this, "_peerConnection", void 0); | ||
_defineProperty(this, "_remoteInboundRTP", {}); | ||
_defineProperty(this, "_remoteOutboundRTP", {}); | ||
_defineProperty(this, "_outboundRTP", {}); | ||
_defineProperty(this, "_inboundRTP", {}); | ||
_defineProperty(this, "_remoteTracks", {}); | ||
_defineProperty(this, "_localTracks", {}); | ||
if (reports.length) { | ||
this.priorReport = reports.shift(); | ||
return stats; | ||
} | ||
}]); | ||
report === null || report === void 0 ? void 0 : report.forEach(function (stat) { | ||
switch (stat.type) { | ||
case RTCStatsTypes.Transport: | ||
_this.transport = stat; | ||
break; | ||
return StatsReport; | ||
}(); | ||
case RTCStatsTypes.RemoteCandidate: | ||
_this.remoteCandidate = stat; | ||
break; | ||
var STATS_COLLECTION_INTERVAL_MS = 5000; | ||
var StatsReporter = /*#__PURE__*/function () { | ||
function StatsReporter(rtcSession, sendStats) { | ||
_classCallCheck(this, StatsReporter); | ||
case RTCStatsTypes.LocalCandidate: | ||
_this.localCandidate = stat; | ||
break; | ||
this.rtcSession = rtcSession; | ||
this.sendStats = sendStats; | ||
case RTCStatsTypes.RemoteInboundRTP: | ||
_this.remoteInboundRTP = stat; | ||
break; | ||
_defineProperty(this, "priorReport", void 0); | ||
case RTCStatsTypes.Codec: | ||
_this.codecs = stat; | ||
break; | ||
case RTCStatsTypes.RemoteOutboundRTP: | ||
_this.remoteOutboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.CandidatePair: | ||
_this.candidatePair = stat; | ||
break; | ||
case RTCStatsTypes.PeerConnection: | ||
_this.peerConnection = stat; | ||
break; | ||
case RTCStatsTypes.OutboundRTP: | ||
_this.outboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.InboundRTP: | ||
_this.inboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.Track: | ||
stat.remoteSource ? _this.remoteTracks = stat : _this.localTracks = stat; | ||
break; | ||
} | ||
}); | ||
this._codecs = this._codecs.filter(function (codec) { | ||
return codec.id === _this._inboundRTP.audio.codecId || codec.id === _this._outboundRTP.audio.codecId || codec.payloadType === 126; | ||
}); | ||
reports.push(this); | ||
_defineProperty(this, "statsTimeout", 0); | ||
} | ||
_createClass(StatsReport, [{ | ||
key: "mos", | ||
value: function mos() { | ||
var _this$priorReport, _this$priorReport$_re; | ||
_createClass(StatsReporter, [{ | ||
key: "getAndSendStats", | ||
value: function () { | ||
var _getAndSendStats = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() { | ||
var stats, statsReport; | ||
return _regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
if (this.rtcSession.isEstablished()) { | ||
_context.next = 2; | ||
break; | ||
} | ||
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'audio'; | ||
if (!((_this$priorReport = this.priorReport) === null || _this$priorReport === void 0 ? void 0 : (_this$priorReport$_re = _this$priorReport._remoteInboundRTP) === null || _this$priorReport$_re === void 0 ? void 0 : _this$priorReport$_re[type])) return null; // Parse variables for the current RTP Data | ||
return _context.abrupt("return", Promise.reject(new Error('RTC Session was not established'))); | ||
var _this$_remoteInboundR2 = this._remoteInboundRTP[type], | ||
currentRTT = _this$_remoteInboundR2.roundTripTime, | ||
currentJitter = _this$_remoteInboundR2.jitter, | ||
currentPacketsLost = _this$_remoteInboundR2.packetsLost; // Parse relevant data from the last RTP Data | ||
case 2: | ||
_context.next = 4; | ||
return this.rtcSession.connection.getStats(); | ||
var _this$priorReport$_re2 = this.priorReport._remoteInboundRTP[type], | ||
priorRTT = _this$priorReport$_re2.roundTripTime, | ||
priorPacketsLost = _this$priorReport$_re2.packetsLost; // Average the RTT from the previous report and this report | ||
case 4: | ||
stats = _context.sent; | ||
statsReport = new StatsReport(stats, this.priorReport); | ||
this.sendStats('application/json', JSON.stringify(statsReport)); | ||
var avgLatency = (currentRTT + priorRTT) / 2; // Determine number of packets lost between reports | ||
case 7: | ||
case "end": | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee, this); | ||
})); | ||
var totalPacketsLost = currentPacketsLost - priorPacketsLost; // Calculate the latency | ||
var latency = avgLatency + currentJitter + totalPacketsLost; // TODO: Provide a more accurate R value which factors | ||
// in the audio codec that is being used. | ||
var r = 93.25 - (latency - 120) / 10; | ||
if (latency < 160) { | ||
r = 93.25 - latency / 40; | ||
function getAndSendStats() { | ||
return _getAndSendStats.apply(this, arguments); | ||
} | ||
r -= totalPacketsLost * 2.5; | ||
r = Math.max(r, 0); // Final MOS Score calculation is an approximate | ||
// based on ITU-T G.107, Annex B Recommendation. | ||
var finalR = 1 + 0.035 * r + 0.000007 * r * (r - 60) * (100 - r); | ||
return +finalR.toFixed(1); | ||
return getAndSendStats; | ||
}() | ||
}, { | ||
key: "stopReporting", | ||
value: function stopReporting() { | ||
window.clearTimeout(this.statsTimeout); | ||
} | ||
}, { | ||
key: "data", | ||
get: function get() { | ||
var _this$priorReport2, _this$priorReport2$_r; | ||
key: "startReporting", | ||
value: function startReporting() { | ||
var _this = this; | ||
var stats = [this._transport, this._candidatePair, this._remoteCandidate, this._localCandidate, this._peerConnection].concat(_toConsumableArray(this._codecs), _toConsumableArray(Object.values(this._remoteInboundRTP)), _toConsumableArray(Object.values(this._remoteOutboundRTP)), _toConsumableArray(Object.values(this._outboundRTP)), _toConsumableArray(Object.values(this._inboundRTP)), _toConsumableArray(Object.values(this._remoteTracks)), _toConsumableArray(Object.values(this._localTracks))); | ||
this.statsTimeout = window.setTimeout(function () { | ||
var isEstablished = _this.rtcSession.isEstablished(); | ||
if ((_this$priorReport2 = this.priorReport) === null || _this$priorReport2 === void 0 ? void 0 : (_this$priorReport2$_r = _this$priorReport2._remoteInboundRTP) === null || _this$priorReport2$_r === void 0 ? void 0 : _this$priorReport2$_r.audio) { | ||
stats.push({ | ||
mos: this.mos() | ||
if (!isEstablished) return; | ||
_this.getAndSendStats()["catch"](function () { | ||
// TODO: We need to somehow handle the reports of | ||
// Stats failing | ||
window.clearTimeout(_this.statsTimeout); | ||
})["finally"](function () { | ||
return _this.startReporting(); | ||
}); | ||
} | ||
return stats; | ||
}, STATS_COLLECTION_INTERVAL_MS); | ||
} | ||
}]); | ||
return StatsReport; | ||
return StatsReporter; | ||
}(); | ||
var COLLECTION_INTERVAL = 5000; | ||
var Call = /*#__PURE__*/function () { | ||
@@ -906,2 +998,4 @@ function Call(rtcSession) { | ||
_defineProperty(this, "statsReporter", void 0); | ||
_defineProperty(this, "addTrackListener", function () { | ||
@@ -953,3 +1047,3 @@ if (!_this.rtcSession.connection) { | ||
_this.getConnectionStats(); | ||
_this.statsReporter.startReporting(); | ||
@@ -970,2 +1064,4 @@ _this.setStatus(exports.CallStatus.Accepted); | ||
_this.statsReporter.stopReporting(); | ||
_this.setStatus(exports.CallStatus.Ended); | ||
@@ -1020,2 +1116,3 @@ }); | ||
this.eventEmitter.on('error', function () {}); | ||
this.statsReporter = new StatsReporter(rtcSession, this.sendInfoMessage); | ||
} | ||
@@ -1052,26 +1149,11 @@ | ||
key: "sendInfoMessage", | ||
value: function sendInfoMessage(message) { | ||
value: function sendInfoMessage(contentType, message) { | ||
if (this.status === exports.CallStatus.Failed) return; | ||
this.rtcSession.sendInfo('application/json', JSON.stringify(message)); | ||
this.rtcSession.sendInfo(contentType, message); | ||
} | ||
}, { | ||
key: "getAndSendStats", | ||
value: function getAndSendStats() { | ||
var _this2 = this; | ||
if (!this.rtcSession.isEstablished()) { | ||
return Promise.reject(new Error('RTC Session was not established')); | ||
} | ||
return this.rtcSession.connection.getStats().then(function (report) { | ||
var statsReport = new StatsReport(report); | ||
_this2.sendInfoMessage(statsReport); | ||
}); | ||
} | ||
}, { | ||
key: "getConnectionStats", | ||
key: "setInputSource", | ||
value: function () { | ||
var _getConnectionStats = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() { | ||
var _this3 = this; | ||
var _setInputSource = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(constraints) { | ||
var senders, nextStream, nextTracks, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _sender$track, sender, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, track; | ||
@@ -1082,40 +1164,4 @@ return _regeneratorRuntime.wrap(function _callee$(_context) { | ||
case 0: | ||
this.statsTimeout = window.setTimeout(function () { | ||
var isEstablished = _this3.rtcSession.isEstablished(); | ||
if (!isEstablished) return; | ||
_this3.getAndSendStats()["catch"](function () { | ||
window.clearTimeout(_this3.statsTimeout); | ||
})["finally"](function () { | ||
return _this3.getConnectionStats(); | ||
}); | ||
}, COLLECTION_INTERVAL); | ||
case 1: | ||
case "end": | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee, this); | ||
})); | ||
function getConnectionStats() { | ||
return _getConnectionStats.apply(this, arguments); | ||
} | ||
return getConnectionStats; | ||
}() | ||
}, { | ||
key: "setInputSource", | ||
value: function () { | ||
var _setInputSource = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(constraints) { | ||
var senders, nextStream, nextTracks, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _sender$track, sender, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, track; | ||
return _regeneratorRuntime.wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
if (this.rtcSession.connection) { | ||
_context2.next = 2; | ||
_context.next = 2; | ||
break; | ||
@@ -1130,12 +1176,12 @@ } | ||
_context2.next = 5; | ||
_context.next = 5; | ||
return navigator.mediaDevices.getUserMedia(constraints); | ||
case 5: | ||
nextStream = _context2.sent; | ||
_context2.next = 8; | ||
nextStream = _context.sent; | ||
_context.next = 8; | ||
return nextStream.getTracks(); | ||
case 8: | ||
nextTracks = _context2.sent; // Iterate through the list of track senders | ||
nextTracks = _context.sent; // Iterate through the list of track senders | ||
@@ -1145,3 +1191,3 @@ _iteratorNormalCompletion = true; | ||
_iteratorError = undefined; | ||
_context2.prev = 12; | ||
_context.prev = 12; | ||
_iterator = senders[Symbol.iterator](); | ||
@@ -1151,3 +1197,3 @@ | ||
if (_iteratorNormalCompletion = (_step = _iterator.next()).done) { | ||
_context2.next = 46; | ||
_context.next = 46; | ||
break; | ||
@@ -1164,3 +1210,3 @@ } | ||
_iteratorError2 = undefined; | ||
_context2.prev = 20; | ||
_context.prev = 20; | ||
_iterator2 = nextTracks[Symbol.iterator](); | ||
@@ -1170,3 +1216,3 @@ | ||
if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) { | ||
_context2.next = 29; | ||
_context.next = 29; | ||
break; | ||
@@ -1176,3 +1222,3 @@ } | ||
track = _step2.value; | ||
_context2.next = 26; | ||
_context.next = 26; | ||
return sender.replaceTrack(track); | ||
@@ -1182,18 +1228,18 @@ | ||
_iteratorNormalCompletion2 = true; | ||
_context2.next = 22; | ||
_context.next = 22; | ||
break; | ||
case 29: | ||
_context2.next = 35; | ||
_context.next = 35; | ||
break; | ||
case 31: | ||
_context2.prev = 31; | ||
_context2.t0 = _context2["catch"](20); | ||
_context.prev = 31; | ||
_context.t0 = _context["catch"](20); | ||
_didIteratorError2 = true; | ||
_iteratorError2 = _context2.t0; | ||
_iteratorError2 = _context.t0; | ||
case 35: | ||
_context2.prev = 35; | ||
_context2.prev = 36; | ||
_context.prev = 35; | ||
_context.prev = 36; | ||
@@ -1205,6 +1251,6 @@ if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) { | ||
case 38: | ||
_context2.prev = 38; | ||
_context.prev = 38; | ||
if (!_didIteratorError2) { | ||
_context2.next = 41; | ||
_context.next = 41; | ||
break; | ||
@@ -1216,25 +1262,25 @@ } | ||
case 41: | ||
return _context2.finish(38); | ||
return _context.finish(38); | ||
case 42: | ||
return _context2.finish(35); | ||
return _context.finish(35); | ||
case 43: | ||
_iteratorNormalCompletion = true; | ||
_context2.next = 14; | ||
_context.next = 14; | ||
break; | ||
case 46: | ||
_context2.next = 52; | ||
_context.next = 52; | ||
break; | ||
case 48: | ||
_context2.prev = 48; | ||
_context2.t1 = _context2["catch"](12); | ||
_context.prev = 48; | ||
_context.t1 = _context["catch"](12); | ||
_didIteratorError = true; | ||
_iteratorError = _context2.t1; | ||
_iteratorError = _context.t1; | ||
case 52: | ||
_context2.prev = 52; | ||
_context2.prev = 53; | ||
_context.prev = 52; | ||
_context.prev = 53; | ||
@@ -1246,6 +1292,6 @@ if (!_iteratorNormalCompletion && _iterator["return"] != null) { | ||
case 55: | ||
_context2.prev = 55; | ||
_context.prev = 55; | ||
if (!_didIteratorError) { | ||
_context2.next = 58; | ||
_context.next = 58; | ||
break; | ||
@@ -1257,13 +1303,13 @@ } | ||
case 58: | ||
return _context2.finish(55); | ||
return _context.finish(55); | ||
case 59: | ||
return _context2.finish(52); | ||
return _context.finish(52); | ||
case 60: | ||
case "end": | ||
return _context2.stop(); | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee2, this, [[12, 48, 52, 60], [20, 31, 35, 43], [36,, 38, 42], [53,, 55, 59]]); | ||
}, _callee, this, [[12, 48, 52, 60], [20, 31, 35, 43], [36,, 38, 42], [53,, 55, 59]]); | ||
})); | ||
@@ -1270,0 +1316,0 @@ |
@@ -10,4 +10,3 @@ import _regeneratorRuntime from "@babel/runtime/regenerator"; | ||
import { isValidDTmfInput } from "./helpers.js"; | ||
import { StatsReport } from "./StatsReport.js"; | ||
var COLLECTION_INTERVAL = 5000; | ||
import { StatsReporter } from "./StatsReporter.js"; | ||
export var Call = /*#__PURE__*/function () { | ||
@@ -33,2 +32,4 @@ function Call(rtcSession) { | ||
_defineProperty(this, "statsReporter", void 0); | ||
_defineProperty(this, "addTrackListener", function () { | ||
@@ -80,3 +81,3 @@ if (!_this.rtcSession.connection) { | ||
_this.getConnectionStats(); | ||
_this.statsReporter.startReporting(); | ||
@@ -97,2 +98,4 @@ _this.setStatus(CallStatus.Accepted); | ||
_this.statsReporter.stopReporting(); | ||
_this.setStatus(CallStatus.Ended); | ||
@@ -147,2 +150,3 @@ }); | ||
this.eventEmitter.on('error', function () {}); | ||
this.statsReporter = new StatsReporter(rtcSession, this.sendInfoMessage); | ||
} | ||
@@ -179,26 +183,11 @@ | ||
key: "sendInfoMessage", | ||
value: function sendInfoMessage(message) { | ||
value: function sendInfoMessage(contentType, message) { | ||
if (this.status === CallStatus.Failed) return; | ||
this.rtcSession.sendInfo('application/json', JSON.stringify(message)); | ||
this.rtcSession.sendInfo(contentType, message); | ||
} | ||
}, { | ||
key: "getAndSendStats", | ||
value: function getAndSendStats() { | ||
var _this2 = this; | ||
if (!this.rtcSession.isEstablished()) { | ||
return Promise.reject(new Error('RTC Session was not established')); | ||
} | ||
return this.rtcSession.connection.getStats().then(function (report) { | ||
var statsReport = new StatsReport(report); | ||
_this2.sendInfoMessage(statsReport); | ||
}); | ||
} | ||
}, { | ||
key: "getConnectionStats", | ||
key: "setInputSource", | ||
value: function () { | ||
var _getConnectionStats = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() { | ||
var _this3 = this; | ||
var _setInputSource = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(constraints) { | ||
var senders, nextStream, nextTracks, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _sender$track, sender, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, track; | ||
@@ -209,40 +198,4 @@ return _regeneratorRuntime.wrap(function _callee$(_context) { | ||
case 0: | ||
this.statsTimeout = window.setTimeout(function () { | ||
var isEstablished = _this3.rtcSession.isEstablished(); | ||
if (!isEstablished) return; | ||
_this3.getAndSendStats()["catch"](function () { | ||
window.clearTimeout(_this3.statsTimeout); | ||
})["finally"](function () { | ||
return _this3.getConnectionStats(); | ||
}); | ||
}, COLLECTION_INTERVAL); | ||
case 1: | ||
case "end": | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee, this); | ||
})); | ||
function getConnectionStats() { | ||
return _getConnectionStats.apply(this, arguments); | ||
} | ||
return getConnectionStats; | ||
}() | ||
}, { | ||
key: "setInputSource", | ||
value: function () { | ||
var _setInputSource = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(constraints) { | ||
var senders, nextStream, nextTracks, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _sender$track, sender, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, track; | ||
return _regeneratorRuntime.wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
if (this.rtcSession.connection) { | ||
_context2.next = 2; | ||
_context.next = 2; | ||
break; | ||
@@ -257,12 +210,12 @@ } | ||
_context2.next = 5; | ||
_context.next = 5; | ||
return navigator.mediaDevices.getUserMedia(constraints); | ||
case 5: | ||
nextStream = _context2.sent; | ||
_context2.next = 8; | ||
nextStream = _context.sent; | ||
_context.next = 8; | ||
return nextStream.getTracks(); | ||
case 8: | ||
nextTracks = _context2.sent; | ||
nextTracks = _context.sent; | ||
// Iterate through the list of track senders | ||
@@ -272,3 +225,3 @@ _iteratorNormalCompletion = true; | ||
_iteratorError = undefined; | ||
_context2.prev = 12; | ||
_context.prev = 12; | ||
_iterator = senders[Symbol.iterator](); | ||
@@ -278,3 +231,3 @@ | ||
if (_iteratorNormalCompletion = (_step = _iterator.next()).done) { | ||
_context2.next = 46; | ||
_context.next = 46; | ||
break; | ||
@@ -291,3 +244,3 @@ } | ||
_iteratorError2 = undefined; | ||
_context2.prev = 20; | ||
_context.prev = 20; | ||
_iterator2 = nextTracks[Symbol.iterator](); | ||
@@ -297,3 +250,3 @@ | ||
if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) { | ||
_context2.next = 29; | ||
_context.next = 29; | ||
break; | ||
@@ -303,3 +256,3 @@ } | ||
track = _step2.value; | ||
_context2.next = 26; | ||
_context.next = 26; | ||
return sender.replaceTrack(track); | ||
@@ -309,18 +262,18 @@ | ||
_iteratorNormalCompletion2 = true; | ||
_context2.next = 22; | ||
_context.next = 22; | ||
break; | ||
case 29: | ||
_context2.next = 35; | ||
_context.next = 35; | ||
break; | ||
case 31: | ||
_context2.prev = 31; | ||
_context2.t0 = _context2["catch"](20); | ||
_context.prev = 31; | ||
_context.t0 = _context["catch"](20); | ||
_didIteratorError2 = true; | ||
_iteratorError2 = _context2.t0; | ||
_iteratorError2 = _context.t0; | ||
case 35: | ||
_context2.prev = 35; | ||
_context2.prev = 36; | ||
_context.prev = 35; | ||
_context.prev = 36; | ||
@@ -332,6 +285,6 @@ if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) { | ||
case 38: | ||
_context2.prev = 38; | ||
_context.prev = 38; | ||
if (!_didIteratorError2) { | ||
_context2.next = 41; | ||
_context.next = 41; | ||
break; | ||
@@ -343,25 +296,25 @@ } | ||
case 41: | ||
return _context2.finish(38); | ||
return _context.finish(38); | ||
case 42: | ||
return _context2.finish(35); | ||
return _context.finish(35); | ||
case 43: | ||
_iteratorNormalCompletion = true; | ||
_context2.next = 14; | ||
_context.next = 14; | ||
break; | ||
case 46: | ||
_context2.next = 52; | ||
_context.next = 52; | ||
break; | ||
case 48: | ||
_context2.prev = 48; | ||
_context2.t1 = _context2["catch"](12); | ||
_context.prev = 48; | ||
_context.t1 = _context["catch"](12); | ||
_didIteratorError = true; | ||
_iteratorError = _context2.t1; | ||
_iteratorError = _context.t1; | ||
case 52: | ||
_context2.prev = 52; | ||
_context2.prev = 53; | ||
_context.prev = 52; | ||
_context.prev = 53; | ||
@@ -373,6 +326,6 @@ if (!_iteratorNormalCompletion && _iterator["return"] != null) { | ||
case 55: | ||
_context2.prev = 55; | ||
_context.prev = 55; | ||
if (!_didIteratorError) { | ||
_context2.next = 58; | ||
_context.next = 58; | ||
break; | ||
@@ -384,13 +337,13 @@ } | ||
case 58: | ||
return _context2.finish(55); | ||
return _context.finish(55); | ||
case 59: | ||
return _context2.finish(52); | ||
return _context.finish(52); | ||
case 60: | ||
case "end": | ||
return _context2.stop(); | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee2, this, [[12, 48, 52, 60], [20, 31, 35, 43], [36,, 38, 42], [53,, 55, 59]]); | ||
}, _callee, this, [[12, 48, 52, 60], [20, 31, 35, 43], [36,, 38, 42], [53,, 55, 59]]); | ||
})); | ||
@@ -397,0 +350,0 @@ |
@@ -19,3 +19,3 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty"; | ||
export function getSDKVersionHeader() { | ||
var version = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "1078f707" || 'HEAD'; | ||
var version = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "b1598330" || 'HEAD'; | ||
return "SDK-Version: ".concat(version); | ||
@@ -22,0 +22,0 @@ } |
@@ -6,5 +6,144 @@ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray"; | ||
import { IceCandidatePairStates, RTCStatsTypes } from "./types/StatsReport.js"; | ||
var reports = []; | ||
export var StatsReport = /*#__PURE__*/function () { | ||
function StatsReport(report, priorReport) { | ||
var _this = this; | ||
_classCallCheck(this, StatsReport); | ||
_defineProperty(this, "priorReport", void 0); | ||
_defineProperty(this, "_transport", void 0); | ||
_defineProperty(this, "_remoteCandidate", void 0); | ||
_defineProperty(this, "_localCandidate", void 0); | ||
_defineProperty(this, "_codecs", []); | ||
_defineProperty(this, "_candidatePair", void 0); | ||
_defineProperty(this, "_peerConnection", void 0); | ||
_defineProperty(this, "_remoteInboundRTP", {}); | ||
_defineProperty(this, "_remoteOutboundRTP", {}); | ||
_defineProperty(this, "_outboundRTP", {}); | ||
_defineProperty(this, "_inboundRTP", {}); | ||
_defineProperty(this, "_remoteTracks", {}); | ||
_defineProperty(this, "_localTracks", {}); | ||
this.priorReport = this.trimPriorReport(priorReport); | ||
report === null || report === void 0 ? void 0 : report.forEach(function (stat) { | ||
switch (stat.type) { | ||
case RTCStatsTypes.Transport: | ||
_this.transport = stat; | ||
break; | ||
case RTCStatsTypes.RemoteCandidate: | ||
_this.remoteCandidate = stat; | ||
break; | ||
case RTCStatsTypes.LocalCandidate: | ||
_this.localCandidate = stat; | ||
break; | ||
case RTCStatsTypes.RemoteInboundRTP: | ||
_this.remoteInboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.Codec: | ||
_this.codecs = stat; | ||
break; | ||
case RTCStatsTypes.RemoteOutboundRTP: | ||
_this.remoteOutboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.CandidatePair: | ||
_this.candidatePair = stat; | ||
break; | ||
case RTCStatsTypes.PeerConnection: | ||
_this.peerConnection = stat; | ||
break; | ||
case RTCStatsTypes.OutboundRTP: | ||
_this.outboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.InboundRTP: | ||
_this.inboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.Track: | ||
stat.remoteSource ? _this.remoteTracks = stat : _this.localTracks = stat; | ||
break; | ||
} | ||
}); | ||
this._codecs = this._codecs.filter(function (codec) { | ||
return codec.id === _this._inboundRTP.audio.codecId || codec.id === _this._outboundRTP.audio.codecId || codec.payloadType === 126; | ||
}); | ||
} | ||
_createClass(StatsReport, [{ | ||
key: "trimPriorReport", | ||
value: function trimPriorReport(priorReport) { | ||
var _priorReport$priorRep; | ||
if (priorReport === undefined) { | ||
return priorReport; | ||
} // The stats reports object contains a "priorReport" which | ||
// Then contains another object with the key "priorReport". | ||
// We don't want to end up with an infinite stream of prior reports | ||
// So we remove the prior report after 2 levels of nesting. | ||
if ((_priorReport$priorRep = priorReport.priorReport) === null || _priorReport$priorRep === void 0 ? void 0 : _priorReport$priorRep.priorReport) { | ||
delete priorReport.priorReport.priorReport; | ||
} | ||
return priorReport; | ||
} | ||
}, { | ||
key: "mos", | ||
value: function mos() { | ||
var _this$priorReport, _this$priorReport$_re; | ||
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'audio'; | ||
if (!((_this$priorReport = this.priorReport) === null || _this$priorReport === void 0 ? void 0 : (_this$priorReport$_re = _this$priorReport._remoteInboundRTP) === null || _this$priorReport$_re === void 0 ? void 0 : _this$priorReport$_re[type])) return null; // Parse variables for the current RTP Data | ||
var _this$_remoteInboundR = this._remoteInboundRTP[type], | ||
currentRTT = _this$_remoteInboundR.roundTripTime, | ||
currentJitter = _this$_remoteInboundR.jitter, | ||
currentPacketsLost = _this$_remoteInboundR.packetsLost; // Parse relevant data from the last RTP Data | ||
var _this$priorReport$_re2 = this.priorReport._remoteInboundRTP[type], | ||
priorRTT = _this$priorReport$_re2.roundTripTime, | ||
priorPacketsLost = _this$priorReport$_re2.packetsLost; // Average the RTT from the previous report and this report | ||
var avgLatency = (currentRTT + priorRTT) / 2; // Determine number of packets lost between reports | ||
var totalPacketsLost = currentPacketsLost - priorPacketsLost; // Calculate the latency | ||
var latency = avgLatency + currentJitter + totalPacketsLost; // TODO: Provide a more accurate R value which factors | ||
// in the audio codec that is being used. | ||
var r = 93.25 - (latency - 120) / 10; | ||
if (latency < 160) { | ||
r = 93.25 - latency / 40; | ||
} | ||
r -= totalPacketsLost * 2.5; | ||
r = Math.max(r, 0); // Final MOS Score calculation is an approximate | ||
// based on ITU-T G.107, Annex B Recommendation. | ||
var finalR = 1 + 0.035 * r + 0.000007 * r * (r - 60) * (100 - r); | ||
return +finalR.toFixed(1); | ||
} | ||
}, { | ||
key: "transport", | ||
@@ -178,129 +317,2 @@ set: function set(stat) { | ||
} | ||
}]); | ||
function StatsReport(report) { | ||
var _this = this; | ||
_classCallCheck(this, StatsReport); | ||
_defineProperty(this, "priorReport", void 0); | ||
_defineProperty(this, "_transport", void 0); | ||
_defineProperty(this, "_remoteCandidate", void 0); | ||
_defineProperty(this, "_localCandidate", void 0); | ||
_defineProperty(this, "_codecs", []); | ||
_defineProperty(this, "_candidatePair", void 0); | ||
_defineProperty(this, "_peerConnection", void 0); | ||
_defineProperty(this, "_remoteInboundRTP", {}); | ||
_defineProperty(this, "_remoteOutboundRTP", {}); | ||
_defineProperty(this, "_outboundRTP", {}); | ||
_defineProperty(this, "_inboundRTP", {}); | ||
_defineProperty(this, "_remoteTracks", {}); | ||
_defineProperty(this, "_localTracks", {}); | ||
if (reports.length) { | ||
this.priorReport = reports.shift(); | ||
} | ||
report === null || report === void 0 ? void 0 : report.forEach(function (stat) { | ||
switch (stat.type) { | ||
case RTCStatsTypes.Transport: | ||
_this.transport = stat; | ||
break; | ||
case RTCStatsTypes.RemoteCandidate: | ||
_this.remoteCandidate = stat; | ||
break; | ||
case RTCStatsTypes.LocalCandidate: | ||
_this.localCandidate = stat; | ||
break; | ||
case RTCStatsTypes.RemoteInboundRTP: | ||
_this.remoteInboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.Codec: | ||
_this.codecs = stat; | ||
break; | ||
case RTCStatsTypes.RemoteOutboundRTP: | ||
_this.remoteOutboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.CandidatePair: | ||
_this.candidatePair = stat; | ||
break; | ||
case RTCStatsTypes.PeerConnection: | ||
_this.peerConnection = stat; | ||
break; | ||
case RTCStatsTypes.OutboundRTP: | ||
_this.outboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.InboundRTP: | ||
_this.inboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.Track: | ||
stat.remoteSource ? _this.remoteTracks = stat : _this.localTracks = stat; | ||
break; | ||
} | ||
}); | ||
this._codecs = this._codecs.filter(function (codec) { | ||
return codec.id === _this._inboundRTP.audio.codecId || codec.id === _this._outboundRTP.audio.codecId || codec.payloadType === 126; | ||
}); | ||
reports.push(this); | ||
} | ||
_createClass(StatsReport, [{ | ||
key: "mos", | ||
value: function mos() { | ||
var _this$priorReport, _this$priorReport$_re; | ||
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'audio'; | ||
if (!((_this$priorReport = this.priorReport) === null || _this$priorReport === void 0 ? void 0 : (_this$priorReport$_re = _this$priorReport._remoteInboundRTP) === null || _this$priorReport$_re === void 0 ? void 0 : _this$priorReport$_re[type])) return null; // Parse variables for the current RTP Data | ||
var _this$_remoteInboundR2 = this._remoteInboundRTP[type], | ||
currentRTT = _this$_remoteInboundR2.roundTripTime, | ||
currentJitter = _this$_remoteInboundR2.jitter, | ||
currentPacketsLost = _this$_remoteInboundR2.packetsLost; // Parse relevant data from the last RTP Data | ||
var _this$priorReport$_re2 = this.priorReport._remoteInboundRTP[type], | ||
priorRTT = _this$priorReport$_re2.roundTripTime, | ||
priorPacketsLost = _this$priorReport$_re2.packetsLost; // Average the RTT from the previous report and this report | ||
var avgLatency = (currentRTT + priorRTT) / 2; // Determine number of packets lost between reports | ||
var totalPacketsLost = currentPacketsLost - priorPacketsLost; // Calculate the latency | ||
var latency = avgLatency + currentJitter + totalPacketsLost; // TODO: Provide a more accurate R value which factors | ||
// in the audio codec that is being used. | ||
var r = 93.25 - (latency - 120) / 10; | ||
if (latency < 160) { | ||
r = 93.25 - latency / 40; | ||
} | ||
r -= totalPacketsLost * 2.5; | ||
r = Math.max(r, 0); // Final MOS Score calculation is an approximate | ||
// based on ITU-T G.107, Annex B Recommendation. | ||
var finalR = 1 + 0.035 * r + 0.000007 * r * (r - 60) * (100 - r); | ||
return +finalR.toFixed(1); | ||
} | ||
}, { | ||
@@ -307,0 +319,0 @@ key: "data", |
@@ -12,2 +12,3 @@ import { RTCSession as SipRTCSession, AnswerOptions } from 'jssip'; | ||
streamTargets: StreamTargets; | ||
private statsReporter; | ||
constructor(rtcSession: SipRTCSession); | ||
@@ -37,6 +38,4 @@ on(name: 'status', cb: (data: CallStatus) => void): void; | ||
mute: (muted: boolean) => void; | ||
sendInfoMessage(message: any): void; | ||
private getAndSendStats; | ||
private getConnectionStats; | ||
sendInfoMessage(contentType: string, message: string): void; | ||
setInputSource(constraints: MediaStreamConstraints): Promise<void>; | ||
} |
@@ -0,3 +1,4 @@ | ||
declare type PriorReport = StatsReport | undefined; | ||
export declare class StatsReport { | ||
private priorReport; | ||
priorReport: PriorReport; | ||
private _transport; | ||
@@ -15,2 +16,4 @@ private _remoteCandidate; | ||
private _localTracks; | ||
constructor(report: RTCStatsReport, priorReport?: PriorReport); | ||
private trimPriorReport; | ||
private set transport(value); | ||
@@ -28,5 +31,5 @@ private set remoteCandidate(value); | ||
private set localTracks(value); | ||
constructor(report: RTCStatsReport); | ||
private mos; | ||
get data(): any[]; | ||
} | ||
export {}; |
@@ -45,3 +45,3 @@ import { UA, WebSocketInterface, debug } from 'jssip'; | ||
function getSDKVersionHeader() { | ||
var version = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "1078f707" ; | ||
var version = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "b1598330" ; | ||
return "SDK-Version: ".concat(version); | ||
@@ -537,5 +537,144 @@ } | ||
var reports = []; | ||
var StatsReport = /*#__PURE__*/function () { | ||
function StatsReport(report, priorReport) { | ||
var _this = this; | ||
_classCallCheck(this, StatsReport); | ||
_defineProperty(this, "priorReport", void 0); | ||
_defineProperty(this, "_transport", void 0); | ||
_defineProperty(this, "_remoteCandidate", void 0); | ||
_defineProperty(this, "_localCandidate", void 0); | ||
_defineProperty(this, "_codecs", []); | ||
_defineProperty(this, "_candidatePair", void 0); | ||
_defineProperty(this, "_peerConnection", void 0); | ||
_defineProperty(this, "_remoteInboundRTP", {}); | ||
_defineProperty(this, "_remoteOutboundRTP", {}); | ||
_defineProperty(this, "_outboundRTP", {}); | ||
_defineProperty(this, "_inboundRTP", {}); | ||
_defineProperty(this, "_remoteTracks", {}); | ||
_defineProperty(this, "_localTracks", {}); | ||
this.priorReport = this.trimPriorReport(priorReport); | ||
report === null || report === void 0 ? void 0 : report.forEach(function (stat) { | ||
switch (stat.type) { | ||
case RTCStatsTypes.Transport: | ||
_this.transport = stat; | ||
break; | ||
case RTCStatsTypes.RemoteCandidate: | ||
_this.remoteCandidate = stat; | ||
break; | ||
case RTCStatsTypes.LocalCandidate: | ||
_this.localCandidate = stat; | ||
break; | ||
case RTCStatsTypes.RemoteInboundRTP: | ||
_this.remoteInboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.Codec: | ||
_this.codecs = stat; | ||
break; | ||
case RTCStatsTypes.RemoteOutboundRTP: | ||
_this.remoteOutboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.CandidatePair: | ||
_this.candidatePair = stat; | ||
break; | ||
case RTCStatsTypes.PeerConnection: | ||
_this.peerConnection = stat; | ||
break; | ||
case RTCStatsTypes.OutboundRTP: | ||
_this.outboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.InboundRTP: | ||
_this.inboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.Track: | ||
stat.remoteSource ? _this.remoteTracks = stat : _this.localTracks = stat; | ||
break; | ||
} | ||
}); | ||
this._codecs = this._codecs.filter(function (codec) { | ||
return codec.id === _this._inboundRTP.audio.codecId || codec.id === _this._outboundRTP.audio.codecId || codec.payloadType === 126; | ||
}); | ||
} | ||
_createClass(StatsReport, [{ | ||
key: "trimPriorReport", | ||
value: function trimPriorReport(priorReport) { | ||
var _priorReport$priorRep; | ||
if (priorReport === undefined) { | ||
return priorReport; | ||
} // The stats reports object contains a "priorReport" which | ||
// Then contains another object with the key "priorReport". | ||
// We don't want to end up with an infinite stream of prior reports | ||
// So we remove the prior report after 2 levels of nesting. | ||
if ((_priorReport$priorRep = priorReport.priorReport) === null || _priorReport$priorRep === void 0 ? void 0 : _priorReport$priorRep.priorReport) { | ||
delete priorReport.priorReport.priorReport; | ||
} | ||
return priorReport; | ||
} | ||
}, { | ||
key: "mos", | ||
value: function mos() { | ||
var _this$priorReport, _this$priorReport$_re; | ||
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'audio'; | ||
if (!((_this$priorReport = this.priorReport) === null || _this$priorReport === void 0 ? void 0 : (_this$priorReport$_re = _this$priorReport._remoteInboundRTP) === null || _this$priorReport$_re === void 0 ? void 0 : _this$priorReport$_re[type])) return null; // Parse variables for the current RTP Data | ||
var _this$_remoteInboundR = this._remoteInboundRTP[type], | ||
currentRTT = _this$_remoteInboundR.roundTripTime, | ||
currentJitter = _this$_remoteInboundR.jitter, | ||
currentPacketsLost = _this$_remoteInboundR.packetsLost; // Parse relevant data from the last RTP Data | ||
var _this$priorReport$_re2 = this.priorReport._remoteInboundRTP[type], | ||
priorRTT = _this$priorReport$_re2.roundTripTime, | ||
priorPacketsLost = _this$priorReport$_re2.packetsLost; // Average the RTT from the previous report and this report | ||
var avgLatency = (currentRTT + priorRTT) / 2; // Determine number of packets lost between reports | ||
var totalPacketsLost = currentPacketsLost - priorPacketsLost; // Calculate the latency | ||
var latency = avgLatency + currentJitter + totalPacketsLost; // TODO: Provide a more accurate R value which factors | ||
// in the audio codec that is being used. | ||
var r = 93.25 - (latency - 120) / 10; | ||
if (latency < 160) { | ||
r = 93.25 - latency / 40; | ||
} | ||
r -= totalPacketsLost * 2.5; | ||
r = Math.max(r, 0); // Final MOS Score calculation is an approximate | ||
// based on ITU-T G.107, Annex B Recommendation. | ||
var finalR = 1 + 0.035 * r + 0.000007 * r * (r - 60) * (100 - r); | ||
return +finalR.toFixed(1); | ||
} | ||
}, { | ||
key: "transport", | ||
@@ -709,150 +848,103 @@ set: function set(stat) { | ||
} | ||
}]); | ||
}, { | ||
key: "data", | ||
get: function get() { | ||
var _this$priorReport2, _this$priorReport2$_r; | ||
function StatsReport(report) { | ||
var _this = this; | ||
var stats = [this._transport, this._candidatePair, this._remoteCandidate, this._localCandidate, this._peerConnection].concat(_toConsumableArray(this._codecs), _toConsumableArray(Object.values(this._remoteInboundRTP)), _toConsumableArray(Object.values(this._remoteOutboundRTP)), _toConsumableArray(Object.values(this._outboundRTP)), _toConsumableArray(Object.values(this._inboundRTP)), _toConsumableArray(Object.values(this._remoteTracks)), _toConsumableArray(Object.values(this._localTracks))); | ||
_classCallCheck(this, StatsReport); | ||
if ((_this$priorReport2 = this.priorReport) === null || _this$priorReport2 === void 0 ? void 0 : (_this$priorReport2$_r = _this$priorReport2._remoteInboundRTP) === null || _this$priorReport2$_r === void 0 ? void 0 : _this$priorReport2$_r.audio) { | ||
stats.push({ | ||
mos: this.mos() | ||
}); | ||
} | ||
_defineProperty(this, "priorReport", void 0); | ||
_defineProperty(this, "_transport", void 0); | ||
_defineProperty(this, "_remoteCandidate", void 0); | ||
_defineProperty(this, "_localCandidate", void 0); | ||
_defineProperty(this, "_codecs", []); | ||
_defineProperty(this, "_candidatePair", void 0); | ||
_defineProperty(this, "_peerConnection", void 0); | ||
_defineProperty(this, "_remoteInboundRTP", {}); | ||
_defineProperty(this, "_remoteOutboundRTP", {}); | ||
_defineProperty(this, "_outboundRTP", {}); | ||
_defineProperty(this, "_inboundRTP", {}); | ||
_defineProperty(this, "_remoteTracks", {}); | ||
_defineProperty(this, "_localTracks", {}); | ||
if (reports.length) { | ||
this.priorReport = reports.shift(); | ||
return stats; | ||
} | ||
}]); | ||
report === null || report === void 0 ? void 0 : report.forEach(function (stat) { | ||
switch (stat.type) { | ||
case RTCStatsTypes.Transport: | ||
_this.transport = stat; | ||
break; | ||
return StatsReport; | ||
}(); | ||
case RTCStatsTypes.RemoteCandidate: | ||
_this.remoteCandidate = stat; | ||
break; | ||
var STATS_COLLECTION_INTERVAL_MS = 5000; | ||
var StatsReporter = /*#__PURE__*/function () { | ||
function StatsReporter(rtcSession, sendStats) { | ||
_classCallCheck(this, StatsReporter); | ||
case RTCStatsTypes.LocalCandidate: | ||
_this.localCandidate = stat; | ||
break; | ||
this.rtcSession = rtcSession; | ||
this.sendStats = sendStats; | ||
case RTCStatsTypes.RemoteInboundRTP: | ||
_this.remoteInboundRTP = stat; | ||
break; | ||
_defineProperty(this, "priorReport", void 0); | ||
case RTCStatsTypes.Codec: | ||
_this.codecs = stat; | ||
break; | ||
case RTCStatsTypes.RemoteOutboundRTP: | ||
_this.remoteOutboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.CandidatePair: | ||
_this.candidatePair = stat; | ||
break; | ||
case RTCStatsTypes.PeerConnection: | ||
_this.peerConnection = stat; | ||
break; | ||
case RTCStatsTypes.OutboundRTP: | ||
_this.outboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.InboundRTP: | ||
_this.inboundRTP = stat; | ||
break; | ||
case RTCStatsTypes.Track: | ||
stat.remoteSource ? _this.remoteTracks = stat : _this.localTracks = stat; | ||
break; | ||
} | ||
}); | ||
this._codecs = this._codecs.filter(function (codec) { | ||
return codec.id === _this._inboundRTP.audio.codecId || codec.id === _this._outboundRTP.audio.codecId || codec.payloadType === 126; | ||
}); | ||
reports.push(this); | ||
_defineProperty(this, "statsTimeout", 0); | ||
} | ||
_createClass(StatsReport, [{ | ||
key: "mos", | ||
value: function mos() { | ||
var _this$priorReport, _this$priorReport$_re; | ||
_createClass(StatsReporter, [{ | ||
key: "getAndSendStats", | ||
value: function () { | ||
var _getAndSendStats = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() { | ||
var stats, statsReport; | ||
return _regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
if (this.rtcSession.isEstablished()) { | ||
_context.next = 2; | ||
break; | ||
} | ||
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'audio'; | ||
if (!((_this$priorReport = this.priorReport) === null || _this$priorReport === void 0 ? void 0 : (_this$priorReport$_re = _this$priorReport._remoteInboundRTP) === null || _this$priorReport$_re === void 0 ? void 0 : _this$priorReport$_re[type])) return null; // Parse variables for the current RTP Data | ||
return _context.abrupt("return", Promise.reject(new Error('RTC Session was not established'))); | ||
var _this$_remoteInboundR2 = this._remoteInboundRTP[type], | ||
currentRTT = _this$_remoteInboundR2.roundTripTime, | ||
currentJitter = _this$_remoteInboundR2.jitter, | ||
currentPacketsLost = _this$_remoteInboundR2.packetsLost; // Parse relevant data from the last RTP Data | ||
case 2: | ||
_context.next = 4; | ||
return this.rtcSession.connection.getStats(); | ||
var _this$priorReport$_re2 = this.priorReport._remoteInboundRTP[type], | ||
priorRTT = _this$priorReport$_re2.roundTripTime, | ||
priorPacketsLost = _this$priorReport$_re2.packetsLost; // Average the RTT from the previous report and this report | ||
case 4: | ||
stats = _context.sent; | ||
statsReport = new StatsReport(stats, this.priorReport); | ||
this.sendStats('application/json', JSON.stringify(statsReport)); | ||
var avgLatency = (currentRTT + priorRTT) / 2; // Determine number of packets lost between reports | ||
case 7: | ||
case "end": | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee, this); | ||
})); | ||
var totalPacketsLost = currentPacketsLost - priorPacketsLost; // Calculate the latency | ||
var latency = avgLatency + currentJitter + totalPacketsLost; // TODO: Provide a more accurate R value which factors | ||
// in the audio codec that is being used. | ||
var r = 93.25 - (latency - 120) / 10; | ||
if (latency < 160) { | ||
r = 93.25 - latency / 40; | ||
function getAndSendStats() { | ||
return _getAndSendStats.apply(this, arguments); | ||
} | ||
r -= totalPacketsLost * 2.5; | ||
r = Math.max(r, 0); // Final MOS Score calculation is an approximate | ||
// based on ITU-T G.107, Annex B Recommendation. | ||
var finalR = 1 + 0.035 * r + 0.000007 * r * (r - 60) * (100 - r); | ||
return +finalR.toFixed(1); | ||
return getAndSendStats; | ||
}() | ||
}, { | ||
key: "stopReporting", | ||
value: function stopReporting() { | ||
window.clearTimeout(this.statsTimeout); | ||
} | ||
}, { | ||
key: "data", | ||
get: function get() { | ||
var _this$priorReport2, _this$priorReport2$_r; | ||
key: "startReporting", | ||
value: function startReporting() { | ||
var _this = this; | ||
var stats = [this._transport, this._candidatePair, this._remoteCandidate, this._localCandidate, this._peerConnection].concat(_toConsumableArray(this._codecs), _toConsumableArray(Object.values(this._remoteInboundRTP)), _toConsumableArray(Object.values(this._remoteOutboundRTP)), _toConsumableArray(Object.values(this._outboundRTP)), _toConsumableArray(Object.values(this._inboundRTP)), _toConsumableArray(Object.values(this._remoteTracks)), _toConsumableArray(Object.values(this._localTracks))); | ||
this.statsTimeout = window.setTimeout(function () { | ||
var isEstablished = _this.rtcSession.isEstablished(); | ||
if ((_this$priorReport2 = this.priorReport) === null || _this$priorReport2 === void 0 ? void 0 : (_this$priorReport2$_r = _this$priorReport2._remoteInboundRTP) === null || _this$priorReport2$_r === void 0 ? void 0 : _this$priorReport2$_r.audio) { | ||
stats.push({ | ||
mos: this.mos() | ||
if (!isEstablished) return; | ||
_this.getAndSendStats()["catch"](function () { | ||
// TODO: We need to somehow handle the reports of | ||
// Stats failing | ||
window.clearTimeout(_this.statsTimeout); | ||
})["finally"](function () { | ||
return _this.startReporting(); | ||
}); | ||
} | ||
return stats; | ||
}, STATS_COLLECTION_INTERVAL_MS); | ||
} | ||
}]); | ||
return StatsReport; | ||
return StatsReporter; | ||
}(); | ||
var COLLECTION_INTERVAL = 5000; | ||
var Call = /*#__PURE__*/function () { | ||
@@ -878,2 +970,4 @@ function Call(rtcSession) { | ||
_defineProperty(this, "statsReporter", void 0); | ||
_defineProperty(this, "addTrackListener", function () { | ||
@@ -925,3 +1019,3 @@ if (!_this.rtcSession.connection) { | ||
_this.getConnectionStats(); | ||
_this.statsReporter.startReporting(); | ||
@@ -942,2 +1036,4 @@ _this.setStatus(CallStatus.Accepted); | ||
_this.statsReporter.stopReporting(); | ||
_this.setStatus(CallStatus.Ended); | ||
@@ -992,2 +1088,3 @@ }); | ||
this.eventEmitter.on('error', function () {}); | ||
this.statsReporter = new StatsReporter(rtcSession, this.sendInfoMessage); | ||
} | ||
@@ -1024,26 +1121,11 @@ | ||
key: "sendInfoMessage", | ||
value: function sendInfoMessage(message) { | ||
value: function sendInfoMessage(contentType, message) { | ||
if (this.status === CallStatus.Failed) return; | ||
this.rtcSession.sendInfo('application/json', JSON.stringify(message)); | ||
this.rtcSession.sendInfo(contentType, message); | ||
} | ||
}, { | ||
key: "getAndSendStats", | ||
value: function getAndSendStats() { | ||
var _this2 = this; | ||
if (!this.rtcSession.isEstablished()) { | ||
return Promise.reject(new Error('RTC Session was not established')); | ||
} | ||
return this.rtcSession.connection.getStats().then(function (report) { | ||
var statsReport = new StatsReport(report); | ||
_this2.sendInfoMessage(statsReport); | ||
}); | ||
} | ||
}, { | ||
key: "getConnectionStats", | ||
key: "setInputSource", | ||
value: function () { | ||
var _getConnectionStats = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() { | ||
var _this3 = this; | ||
var _setInputSource = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(constraints) { | ||
var senders, nextStream, nextTracks, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _sender$track, sender, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, track; | ||
@@ -1054,40 +1136,4 @@ return _regeneratorRuntime.wrap(function _callee$(_context) { | ||
case 0: | ||
this.statsTimeout = window.setTimeout(function () { | ||
var isEstablished = _this3.rtcSession.isEstablished(); | ||
if (!isEstablished) return; | ||
_this3.getAndSendStats()["catch"](function () { | ||
window.clearTimeout(_this3.statsTimeout); | ||
})["finally"](function () { | ||
return _this3.getConnectionStats(); | ||
}); | ||
}, COLLECTION_INTERVAL); | ||
case 1: | ||
case "end": | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee, this); | ||
})); | ||
function getConnectionStats() { | ||
return _getConnectionStats.apply(this, arguments); | ||
} | ||
return getConnectionStats; | ||
}() | ||
}, { | ||
key: "setInputSource", | ||
value: function () { | ||
var _setInputSource = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(constraints) { | ||
var senders, nextStream, nextTracks, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _sender$track, sender, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, track; | ||
return _regeneratorRuntime.wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
if (this.rtcSession.connection) { | ||
_context2.next = 2; | ||
_context.next = 2; | ||
break; | ||
@@ -1102,12 +1148,12 @@ } | ||
_context2.next = 5; | ||
_context.next = 5; | ||
return navigator.mediaDevices.getUserMedia(constraints); | ||
case 5: | ||
nextStream = _context2.sent; | ||
_context2.next = 8; | ||
nextStream = _context.sent; | ||
_context.next = 8; | ||
return nextStream.getTracks(); | ||
case 8: | ||
nextTracks = _context2.sent; | ||
nextTracks = _context.sent; | ||
// Iterate through the list of track senders | ||
@@ -1117,3 +1163,3 @@ _iteratorNormalCompletion = true; | ||
_iteratorError = undefined; | ||
_context2.prev = 12; | ||
_context.prev = 12; | ||
_iterator = senders[Symbol.iterator](); | ||
@@ -1123,3 +1169,3 @@ | ||
if (_iteratorNormalCompletion = (_step = _iterator.next()).done) { | ||
_context2.next = 46; | ||
_context.next = 46; | ||
break; | ||
@@ -1136,3 +1182,3 @@ } | ||
_iteratorError2 = undefined; | ||
_context2.prev = 20; | ||
_context.prev = 20; | ||
_iterator2 = nextTracks[Symbol.iterator](); | ||
@@ -1142,3 +1188,3 @@ | ||
if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) { | ||
_context2.next = 29; | ||
_context.next = 29; | ||
break; | ||
@@ -1148,3 +1194,3 @@ } | ||
track = _step2.value; | ||
_context2.next = 26; | ||
_context.next = 26; | ||
return sender.replaceTrack(track); | ||
@@ -1154,18 +1200,18 @@ | ||
_iteratorNormalCompletion2 = true; | ||
_context2.next = 22; | ||
_context.next = 22; | ||
break; | ||
case 29: | ||
_context2.next = 35; | ||
_context.next = 35; | ||
break; | ||
case 31: | ||
_context2.prev = 31; | ||
_context2.t0 = _context2["catch"](20); | ||
_context.prev = 31; | ||
_context.t0 = _context["catch"](20); | ||
_didIteratorError2 = true; | ||
_iteratorError2 = _context2.t0; | ||
_iteratorError2 = _context.t0; | ||
case 35: | ||
_context2.prev = 35; | ||
_context2.prev = 36; | ||
_context.prev = 35; | ||
_context.prev = 36; | ||
@@ -1177,6 +1223,6 @@ if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) { | ||
case 38: | ||
_context2.prev = 38; | ||
_context.prev = 38; | ||
if (!_didIteratorError2) { | ||
_context2.next = 41; | ||
_context.next = 41; | ||
break; | ||
@@ -1188,25 +1234,25 @@ } | ||
case 41: | ||
return _context2.finish(38); | ||
return _context.finish(38); | ||
case 42: | ||
return _context2.finish(35); | ||
return _context.finish(35); | ||
case 43: | ||
_iteratorNormalCompletion = true; | ||
_context2.next = 14; | ||
_context.next = 14; | ||
break; | ||
case 46: | ||
_context2.next = 52; | ||
_context.next = 52; | ||
break; | ||
case 48: | ||
_context2.prev = 48; | ||
_context2.t1 = _context2["catch"](12); | ||
_context.prev = 48; | ||
_context.t1 = _context["catch"](12); | ||
_didIteratorError = true; | ||
_iteratorError = _context2.t1; | ||
_iteratorError = _context.t1; | ||
case 52: | ||
_context2.prev = 52; | ||
_context2.prev = 53; | ||
_context.prev = 52; | ||
_context.prev = 53; | ||
@@ -1218,6 +1264,6 @@ if (!_iteratorNormalCompletion && _iterator["return"] != null) { | ||
case 55: | ||
_context2.prev = 55; | ||
_context.prev = 55; | ||
if (!_didIteratorError) { | ||
_context2.next = 58; | ||
_context.next = 58; | ||
break; | ||
@@ -1229,13 +1275,13 @@ } | ||
case 58: | ||
return _context2.finish(55); | ||
return _context.finish(55); | ||
case 59: | ||
return _context2.finish(52); | ||
return _context.finish(52); | ||
case 60: | ||
case "end": | ||
return _context2.stop(); | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee2, this, [[12, 48, 52, 60], [20, 31, 35, 43], [36,, 38, 42], [53,, 55, 59]]); | ||
}, _callee, this, [[12, 48, 52, 60], [20, 31, 35, 43], [36,, 38, 42], [53,, 55, 59]]); | ||
})); | ||
@@ -1242,0 +1288,0 @@ |
{ | ||
"name": "@messagebird/client", | ||
"version": "1.0.0-next-rc.4", | ||
"version": "1.0.0-next-rc.5", | ||
"license": "UNLICENSED", | ||
@@ -5,0 +5,0 @@ "files": [ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
445605
54
4845