diff --git a/src/utils/webrtc/analyzers/AverageStatValue.js b/src/utils/webrtc/analyzers/AverageStatValue.js index 5506cacdd11..f691b516529 100644 --- a/src/utils/webrtc/analyzers/AverageStatValue.js +++ b/src/utils/webrtc/analyzers/AverageStatValue.js @@ -55,6 +55,9 @@ const STAT_VALUE_TYPE = { * the raw value that was added or the relative one after the conversion (which, * for non cumulative values, will be the raw value too). * + * A string representation of the current relative values can be got by calling + * "toString()". + * * @param {int} count the number of instances to take into account. * @param {STAT_VALUE_TYPE} type whether the value is cumulative or relative. * @param {int} lastValueWeight the value to calculate the weights of all the @@ -127,6 +130,22 @@ AverageStatValue.prototype = { return weightedValues / weightsSum }, + toString() { + if (!this._relativeValues.length) { + return '[]' + } + + let relativeValuesAsString = '[' + this._relativeValues[0] + + for (let i = 1; i < this._relativeValues.length; i++) { + relativeValuesAsString += ', ' + this._relativeValues[i] + } + + relativeValuesAsString += ']' + + return relativeValuesAsString + }, + } export { diff --git a/src/utils/webrtc/analyzers/AverageStatValue.spec.js b/src/utils/webrtc/analyzers/AverageStatValue.spec.js index d0a31f47f25..c0d8d5745a3 100644 --- a/src/utils/webrtc/analyzers/AverageStatValue.spec.js +++ b/src/utils/webrtc/analyzers/AverageStatValue.spec.js @@ -35,6 +35,43 @@ describe('AverageStatValue', () => { }) }) + describe('to string', () => { + test('no values', () => { + const stat = new AverageStatValue(3, STAT_VALUE_TYPE.CUMULATIVE, 3) + const stat2 = new AverageStatValue(3, STAT_VALUE_TYPE.RELATIVE, 3) + + expect(stat.toString()).toBe('[]') + expect(stat2.toString()).toBe('[]') + }) + + test('single value', () => { + const stat = new AverageStatValue(3, STAT_VALUE_TYPE.CUMULATIVE, 3) + const stat2 = new AverageStatValue(3, STAT_VALUE_TYPE.RELATIVE, 3) + + stat.add(42) + stat2.add(42) + + // The first cumulative value is treated as 0 as it is the base from + // which the rest of the values will be calculated. + expect(stat.toString()).toBe('[0]') + expect(stat2.toString()).toBe('[42]') + }) + + test('several values', () => { + const testValues = [100, 200, 150, 123, 30, 50, 22, 33] + const stat = new AverageStatValue(3, STAT_VALUE_TYPE.CUMULATIVE, 3) + const stat2 = new AverageStatValue(3, STAT_VALUE_TYPE.RELATIVE, 3) + + testValues.forEach((val, index) => { + stat.add(val) + stat2.add(val) + }) + + expect(stat.toString()).toBe('[20, -28, 11]') + expect(stat2.toString()).toBe('[50, 22, 33]') + }) + }) + describe('cumulative average', () => { test('returns the last relative value', () => { const testValues = [ diff --git a/src/utils/webrtc/analyzers/PeerConnectionAnalyzer.js b/src/utils/webrtc/analyzers/PeerConnectionAnalyzer.js index 3580951e0bf..7b8b85cbbc9 100644 --- a/src/utils/webrtc/analyzers/PeerConnectionAnalyzer.js +++ b/src/utils/webrtc/analyzers/PeerConnectionAnalyzer.js @@ -101,6 +101,10 @@ function PeerConnectionAnalyzer() { audio: new AverageStatValue(2, STAT_VALUE_TYPE.CUMULATIVE), video: new AverageStatValue(2, STAT_VALUE_TYPE.CUMULATIVE), } + this._timestampsForLogs = { + audio: new AverageStatValue(5, STAT_VALUE_TYPE.CUMULATIVE), + video: new AverageStatValue(5, STAT_VALUE_TYPE.CUMULATIVE), + } this._analysisEnabled = { audio: true, @@ -224,6 +228,7 @@ PeerConnectionAnalyzer.prototype = { this._packetsLostRatio[kind].reset() this._packetsPerSecond[kind].reset() this._timestamps[kind].reset() + this._timestampsForLogs[kind].reset() }, _handleIceConnectionStateChanged() { @@ -405,6 +410,7 @@ PeerConnectionAnalyzer.prototype = { } if (timestamp[kind] >= 0) { this._timestamps[kind].add(timestamp[kind]) + this._timestampsForLogs[kind].add(timestamp[kind]) } if (packets[kind] >= 0 && timestamp[kind] >= 0) { const elapsedSeconds = this._timestamps[kind].getLastRelativeValue() / 1000 @@ -495,6 +501,7 @@ PeerConnectionAnalyzer.prototype = { } if (timestamp[kind] >= 0) { this._timestamps[kind].add(timestamp[kind]) + this._timestampsForLogs[kind].add(timestamp[kind]) } if (packets[kind] >= 0 && timestamp[kind] >= 0) { const elapsedSeconds = this._timestamps[kind].getLastRelativeValue() / 1000 @@ -507,20 +514,22 @@ PeerConnectionAnalyzer.prototype = { }, _calculateConnectionQualityAudio() { - return this._calculateConnectionQuality(this._packetsLostRatio.audio, this._packetsPerSecond.audio, this._roundTripTime.audio) + return this._calculateConnectionQuality(this._packetsLostRatio.audio, this._packetsPerSecond.audio, this._roundTripTime.audio, 'audio') }, _calculateConnectionQualityVideo() { - return this._calculateConnectionQuality(this._packetsLostRatio.video, this._packetsPerSecond.video, this._roundTripTime.video) + return this._calculateConnectionQuality(this._packetsLostRatio.video, this._packetsPerSecond.video, this._roundTripTime.video, 'video') }, - _calculateConnectionQuality(packetsLostRatio, packetsPerSecond, roundTripTime) { + _calculateConnectionQuality(packetsLostRatio, packetsPerSecond, roundTripTime, kind) { if (!packetsLostRatio.hasEnoughData() || !packetsPerSecond.hasEnoughData()) { return CONNECTION_QUALITY.UNKNOWN } const packetsLostRatioWeightedAverage = packetsLostRatio.getWeightedAverage() if (packetsLostRatioWeightedAverage >= 1) { + this._logStats(kind, 'No transmitted data, packet lost ratio: ' + packetsLostRatioWeightedAverage) + return CONNECTION_QUALITY.NO_TRANSMITTED_DATA } @@ -529,6 +538,8 @@ PeerConnectionAnalyzer.prototype = { // discarded to try to keep the playing rate in real time. // Round trip time is measured in seconds. if (roundTripTime.hasEnoughData() && roundTripTime.getWeightedAverage() > 1.5) { + this._logStats(kind, 'High round trip time: ' + roundTripTime.getWeightedAverage()) + return CONNECTION_QUALITY.VERY_BAD } @@ -544,10 +555,14 @@ PeerConnectionAnalyzer.prototype = { // with a threshold of 10 packets issues can be detected too for videos, // although only once they can not be further downscaled. if (packetsPerSecond.getWeightedAverage() < 10) { + this._logStats(kind, 'Low packets per second: ' + packetsPerSecond.getWeightedAverage()) + return CONNECTION_QUALITY.VERY_BAD } if (packetsLostRatioWeightedAverage > 0.3) { + this._logStats(kind, 'High packet lost ratio: ' + packetsLostRatioWeightedAverage) + return CONNECTION_QUALITY.VERY_BAD } @@ -562,6 +577,21 @@ PeerConnectionAnalyzer.prototype = { return CONNECTION_QUALITY.GOOD }, + _logStats(kind, message) { + const tag = 'PeerConnectionAnalyzer: ' + kind + ': ' + + if (message) { + console.debug(tag + message) + } + + console.debug(tag + 'Packets: ' + this._packets[kind].toString()) + console.debug(tag + 'Packets lost: ' + this._packetsLost[kind].toString()) + console.debug(tag + 'Packets lost ratio: ' + this._packetsLostRatio[kind].toString()) + console.debug(tag + 'Packets per second: ' + this._packetsPerSecond[kind].toString()) + console.debug(tag + 'Round trip time: ' + this._roundTripTime[kind].toString()) + console.debug(tag + 'Timestamps: ' + this._timestampsForLogs[kind].toString()) + }, + } export {