From 501c97b27cee6153181d319d89c54e64ae007f62 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Fri, 28 Nov 2014 19:47:19 +0200 Subject: [PATCH] Implements firefox support for the rtp stats --- rtp_sts.js | 194 ++++++++++++++++++++++++++++++++++++------------- videolayout.js | 26 ++++--- 2 files changed, 159 insertions(+), 61 deletions(-) diff --git a/rtp_sts.js b/rtp_sts.js index c04f4b3d8..289957fdd 100644 --- a/rtp_sts.js +++ b/rtp_sts.js @@ -102,6 +102,7 @@ PeerStats.prototype.setSsrcAudioLevel = function (ssrc, audioLevel) */ PeerStats.transport = []; + /** * StatsCollector registers for stats updates of given * peerconnection in given interval. On each update particular @@ -174,9 +175,15 @@ StatsCollector.prototype.start = function () self.peerconnection.getStats( function (report) { + var results = null; if(!report || !report.result || typeof report.result != 'function') - return; - var results = report.result(); + { + results = report; + } + else + { + results = report.result(); + } //console.error("Got interval report", results); self.currentAudioLevelsReport = results; self.processAudioLevelReport(); @@ -195,12 +202,28 @@ StatsCollector.prototype.start = function () self.peerconnection.getStats( function (report) { + var results = null; if(!report || !report.result || typeof report.result != 'function') - return; - var results = report.result(); + { + //firefox + results = report; + } + else + { + //chrome + results = report.result(); + } //console.error("Got interval report", results); self.currentStatsReport = results; - self.processStatsReport(); + try + { + self.processStatsReport(); + } + catch(e) + { + console.error("Unsupported key:" + e); + } + self.baselineStatsReport = self.currentStatsReport; }, self.errorCallback @@ -210,6 +233,36 @@ StatsCollector.prototype.start = function () ); }; +var keyMap = { + "firefox": { + "ssrc": "ssrc", + "packetsReceived": "packetsReceived", + "packetsLost": "packetsLost", + "packetsSent": "packetsSent", + "bytesReceived": "bytesReceived", + "bytesSent": "bytesSent" + }, + "chrome": { + "receiveBandwidth": "googAvailableReceiveBandwidth", + "sendBandwidth": "googAvailableSendBandwidth", + "remoteAddress": "googRemoteAddress", + "transportType": "googTransportType", + "localAddress": "googLocalAddress", + "activeConnection": "googActiveConnection", + "ssrc": "ssrc", + "packetsReceived": "packetsReceived", + "packetsSent": "packetsSent", + "packetsLost": "packetsLost", + "bytesReceived": "bytesReceived", + "bytesSent": "bytesSent", + "googFrameHeightReceived": "googFrameHeightReceived", + "googFrameWidthReceived": "googFrameWidthReceived", + "googFrameHeightSent": "googFrameHeightSent", + "googFrameWidthSent": "googFrameWidthSent", + "audioInputLevel": "audioInputLevel", + "audioOutputLevel": "audioOutputLevel" + } +}; /** * Stats processing logic. @@ -221,23 +274,29 @@ StatsCollector.prototype.processStatsReport = function () { for (var idx in this.currentStatsReport) { var now = this.currentStatsReport[idx]; - if (now.stat('googAvailableReceiveBandwidth') || - now.stat('googAvailableSendBandwidth')) - { - PeerStats.bandwidth = { - "download": Math.round( - (now.stat('googAvailableReceiveBandwidth')) / 1000), - "upload": Math.round( - (now.stat('googAvailableSendBandwidth')) / 1000) - }; + try { + if (getStatValue(now, 'receiveBandwidth') || + getStatValue(now, 'sendBandwidth')) { + PeerStats.bandwidth = { + "download": Math.round( + (getStatValue(now, 'receiveBandwidth')) / 1000), + "upload": Math.round( + (getStatValue(now, 'sendBandwidth')) / 1000) + }; + } } + catch(e){/*not supported*/} if(now.type == 'googCandidatePair') { - var ip = now.stat('googRemoteAddress'); - var type = now.stat("googTransportType"); - var localIP = now.stat("googLocalAddress"); - var active = now.stat("googActiveConnection"); + var ip, type, localIP, active; + try { + ip = getStatValue(now, 'remoteAddress'); + type = getStatValue(now, "transportType"); + localIP = getStatValue(now, "localAddress"); + active = getStatValue(now, "activeConnection"); + } + catch(e){/*not supported*/} if(!ip || !type || !localIP || active != "true") continue; var addressSaved = false; @@ -256,17 +315,32 @@ StatsCollector.prototype.processStatsReport = function () { continue; } - if (now.type != 'ssrc') { + if(now.type == "candidatepair") + { + if(now.state == "succeeded") + continue; + + var local = this.currentStatsReport[now.localCandidateId]; + var remote = this.currentStatsReport[now.remoteCandidateId]; + PeerStats.transport.push({localip: local.ipAddress + ":" + local.portNumber, + ip: remote.ipAddress + ":" + remote.portNumber, type: local.transport}); + + } + + if (now.type != 'ssrc' && now.type != "outboundrtp" && + now.type != "inboundrtp") { continue; } var before = this.baselineStatsReport[idx]; if (!before) { - console.warn(now.stat('ssrc') + ' not enough data'); + console.warn(getStatValue(now, 'ssrc') + ' not enough data'); continue; } - var ssrc = now.stat('ssrc'); + var ssrc = getStatValue(now, 'ssrc'); + if(!ssrc) + continue; var jid = ssrc2jid[ssrc]; if (!jid) { console.warn("No jid for ssrc: " + ssrc); @@ -282,31 +356,30 @@ StatsCollector.prototype.processStatsReport = function () { var isDownloadStream = true; var key = 'packetsReceived'; - if (!now.stat(key)) + if (!getStatValue(now, key)) { isDownloadStream = false; key = 'packetsSent'; - if (!now.stat(key)) + if (!getStatValue(now, key)) { - console.error("No packetsReceived nor packetSent stat found"); - this.stop(); - return; + console.warn("No packetsReceived nor packetSent stat found"); + continue; } } - var packetsNow = now.stat(key); + var packetsNow = getStatValue(now, key); if(!packetsNow || packetsNow < 0) packetsNow = 0; - var packetsBefore = before.stat(key); + var packetsBefore = getStatValue(before, key); if(!packetsBefore || packetsBefore < 0) packetsBefore = 0; var packetRate = packetsNow - packetsBefore; if(!packetRate || packetRate < 0) packetRate = 0; - var currentLoss = now.stat('packetsLost'); + var currentLoss = getStatValue(now, 'packetsLost'); if(!currentLoss || currentLoss < 0) currentLoss = 0; - var previousLoss = before.stat('packetsLost'); + var previousLoss = getStatValue(before, 'packetsLost'); if(!previousLoss || previousLoss < 0) previousLoss = 0; var lossRate = currentLoss - previousLoss; @@ -320,15 +393,15 @@ StatsCollector.prototype.processStatsReport = function () { "isDownloadStream": isDownloadStream}); var bytesReceived = 0, bytesSent = 0; - if(now.stat("bytesReceived")) + if(getStatValue(now, "bytesReceived")) { - bytesReceived = now.stat("bytesReceived") - - before.stat("bytesReceived"); + bytesReceived = getStatValue(now, "bytesReceived") - + getStatValue(before, "bytesReceived"); } - if(now.stat("bytesSent")) + if(getStatValue(now, "bytesSent")) { - bytesSent = now.stat("bytesSent") - before.stat("bytesSent"); + bytesSent = getStatValue(now, "bytesSent") - getStatValue(before, "bytesSent"); } var time = Math.round((now.timestamp - before.timestamp) / 1000); @@ -354,18 +427,19 @@ StatsCollector.prototype.processStatsReport = function () { "download": bytesReceived, "upload": bytesSent}); var resolution = {height: null, width: null}; - if(now.stat("googFrameHeightReceived") && - now.stat("googFrameWidthReceived")) - { - resolution.height = now.stat("googFrameHeightReceived"); - resolution.width = now.stat("googFrameWidthReceived"); - } - else if(now.stat("googFrameHeightSent") && - now.stat("googFrameWidthSent")) - { - resolution.height = now.stat("googFrameHeightSent"); - resolution.width = now.stat("googFrameWidthSent"); + try { + if (getStatValue(now, "googFrameHeightReceived") && + getStatValue(now, "googFrameWidthReceived")) { + resolution.height = getStatValue(now, "googFrameHeightReceived"); + resolution.width = getStatValue(now, "googFrameWidthReceived"); + } + else if (getStatValue(now, "googFrameHeightSent") && + getStatValue(now, "googFrameWidthSent")) { + resolution.height = getStatValue(now, "googFrameHeightSent"); + resolution.width = getStatValue(now, "googFrameWidthSent"); + } } + catch(e){/*not supported*/} if(resolution.height && resolution.width) { @@ -413,6 +487,7 @@ StatsCollector.prototype.processStatsReport = function () { } ); + console.log("!!!!!!!!!! " + bitrateDownload + " - " + bitrateUpload); PeerStats.bitrate = {"upload": bitrateUpload, "download": bitrateDownload}; PeerStats.packetLoss = { @@ -458,11 +533,11 @@ StatsCollector.prototype.processAudioLevelReport = function () var before = this.baselineAudioLevelsReport[idx]; if (!before) { - console.warn(now.stat('ssrc') + ' not enough data'); + console.warn(getStatValue(now, 'ssrc') + ' not enough data'); continue; } - var ssrc = now.stat('ssrc'); + var ssrc = getStatValue(now, 'ssrc'); var jid = ssrc2jid[ssrc]; if (!jid) { @@ -478,9 +553,19 @@ StatsCollector.prototype.processAudioLevelReport = function () } // Audio level - var audioLevel = now.stat('audioInputLevel'); - if (!audioLevel) - audioLevel = now.stat('audioOutputLevel'); + var audioLevel = null; + + try { + audioLevel = getStatValue(now, 'audioInputLevel'); + if (!audioLevel) + audioLevel = getStatValue(now, 'audioOutputLevel'); + } + catch(e) {/*not supported*/ + console.warn("Audio Levels are not available in the statistics."); + clearInterval(this.audioLevelsIntervalId); + return; + } + if (audioLevel) { // TODO: can't find specs about what this value really is, @@ -495,3 +580,10 @@ StatsCollector.prototype.processAudioLevelReport = function () }; + +function getStatValue(item, name) { + if(!keyMap[RTC.browser][name]) + throw "The property isn't supported!"; + var key = keyMap[RTC.browser][name]; + return RTC.browser == "chrome"? item.stat(key) : item[key]; +} \ No newline at end of file diff --git a/videolayout.js b/videolayout.js index 67e8fd48e..04ad3d18f 100644 --- a/videolayout.js +++ b/videolayout.js @@ -1640,7 +1640,7 @@ var VideoLayout = (function (my) { endpointSimulcastLayers.forEach(function (esl) { var resource = esl.endpoint; - if (lastNCount < 1 || lastNEndpointsCache.indexOf(resource) === -1) { + if (lastNCount !== -1 && (lastNCount < 1 || lastNEndpointsCache.indexOf(resource) === -1)) { return; } @@ -1686,7 +1686,7 @@ var VideoLayout = (function (my) { endpointSimulcastLayers.forEach(function (esl) { var resource = esl.endpoint; - if (lastNCount < 1 || lastNEndpointsCache.indexOf(resource) === -1) { + if (lastNCount !== -1 && (lastNCount < 1 || lastNEndpointsCache.indexOf(resource) === -1)) { return; } @@ -1861,19 +1861,25 @@ var VideoLayout = (function (my) { if(this.jid==null) { resolution = ""; - for(var i in this.resolution) + if(this.resolution == null || !Object.keys(this.resolution) + || Object.keys(this.resolution).length == 0) { - resolutionValue = this.resolution[i]; - if(resolutionValue) + resolution = "N/A"; + } + else + for(var i in this.resolution) { - if(resolutionValue.height && - resolutionValue.width) + resolutionValue = this.resolution[i]; + if(resolutionValue) { - resolution += (resolution == ""? "" : ", ") - + resolutionValue.width + "x" + resolutionValue.height; + if(resolutionValue.height && + resolutionValue.width) + { + resolution += (resolution == ""? "" : ", ") + + resolutionValue.width + "x" + resolutionValue.height; + } } } - } } else if(!resolutionValue || !resolutionValue.height ||