1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/content/aboutWebrtc.xhtml Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,340 @@ 1.4 +<?xml version="1.0" encoding="UTF-8"?> 1.5 +<!-- This Source Code Form is subject to the terms of the Mozilla Public 1.6 + - License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> 1.8 + 1.9 + 1.10 +<!DOCTYPE html [ 1.11 +<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> %htmlDTD; 1.12 +]> 1.13 + 1.14 +<html xmlns="http://www.w3.org/1999/xhtml"> 1.15 + <head> 1.16 + <title>Webrtc Internals</title> 1.17 + </head> 1.18 + <script> 1.19 + 1.20 + 1.21 +function displayLogs(logs) { 1.22 + var logsDiv = document.getElementById('logs'); 1.23 + while (logsDiv.lastChild) { 1.24 + logsDiv.removeChild(logsDiv.lastChild); 1.25 + } 1.26 + logsDiv.appendChild(document.createElement('h3')) 1.27 + .appendChild(document.createTextNode('Logging:')); 1.28 + logs.forEach(function(logLine){ 1.29 + logsDiv.appendChild(document.createElement('div')) 1.30 + .appendChild(document.createTextNode(logLine)); 1.31 + }); 1.32 +} 1.33 + 1.34 +function candidateTypeString(cand) { 1.35 + if (cand.type == "localcandidate") { 1.36 + if (cand.candidateType == "relayed") { 1.37 + return cand.candidateType + '-' + cand.mozLocalTransport; 1.38 + } 1.39 + } 1.40 + return cand.candidateType; 1.41 +} 1.42 + 1.43 +function candidateAddrString(cand) { 1.44 + return cand.ipAddress + ':' + 1.45 + cand.portNumber + '/' + 1.46 + cand.transport + '(' + 1.47 + candidateTypeString(cand) + ')'; 1.48 +} 1.49 + 1.50 +function buildCandPairTableRow(candPair, localCand, remoteCand) { 1.51 + var row = document.createElement('tr'); 1.52 + row.onclick = function() { 1.53 + WebrtcGlobalInformation.getLogging("CAND-PAIR(" + row.id, displayLogs); 1.54 + } 1.55 + 1.56 + if (localCand) { 1.57 + row.appendChild(document.createElement('td')) 1.58 + .appendChild(document.createTextNode(candidateAddrString(localCand))); 1.59 + } else { 1.60 + row.appendChild(document.createElement('td')) 1.61 + .appendChild(document.createTextNode(candPair.localCandidateId)); 1.62 + } 1.63 + 1.64 + if (remoteCand) { 1.65 + row.appendChild(document.createElement('td')) 1.66 + .appendChild(document.createTextNode(candidateAddrString(remoteCand))); 1.67 + } else { 1.68 + row.appendChild(document.createElement('td')) 1.69 + .appendChild(document.createTextNode(candPair.remoteCandidateId)); 1.70 + } 1.71 + 1.72 + row.appendChild(document.createElement('td')) 1.73 + .appendChild(document.createTextNode(candPair.state)); 1.74 + row.appendChild(document.createElement('td')) 1.75 + .appendChild(document.createTextNode(candPair.mozPriority)); 1.76 + 1.77 + row.appendChild(document.createElement('td')) 1.78 + .appendChild(document.createTextNode(candPair.nominated ? '*' : '')); 1.79 + row.appendChild(document.createElement('td')) 1.80 + .appendChild(document.createTextNode(candPair.selected ? '*' : '')); 1.81 + return row; 1.82 +} 1.83 + 1.84 +function buildCandTableRow(cand) { 1.85 + var row = document.createElement('tr'); 1.86 + 1.87 + row.appendChild(document.createElement('td')) 1.88 + .appendChild(document.createTextNode(cand.ipAddress + ':' + 1.89 + cand.portNumber + '/' + 1.90 + cand.transport)); 1.91 + 1.92 + row.appendChild(document.createElement('td')) 1.93 + .appendChild(document.createTextNode(candidateTypeString(cand))); 1.94 + return row; 1.95 +} 1.96 + 1.97 +function buildCandPairTableHeader() { 1.98 + var headerRow = document.createElement('tr'); 1.99 + headerRow.appendChild(document.createElement('th')) 1.100 + .appendChild(document.createTextNode('Local candidate')); 1.101 + headerRow.appendChild(document.createElement('th')) 1.102 + .appendChild(document.createTextNode('Remote candidate')); 1.103 + headerRow.appendChild(document.createElement('th')) 1.104 + .appendChild(document.createTextNode('ICE State')); 1.105 + headerRow.appendChild(document.createElement('th')) 1.106 + .appendChild(document.createTextNode('Priority')); 1.107 + headerRow.appendChild(document.createElement('th')) 1.108 + .appendChild(document.createTextNode('Nominated')); 1.109 + headerRow.appendChild(document.createElement('th')) 1.110 + .appendChild(document.createTextNode('Selected')); 1.111 + return headerRow; 1.112 +} 1.113 + 1.114 +function buildCandTableHeader(isLocal) { 1.115 + var headerRow = document.createElement('tr'); 1.116 + headerRow.appendChild(document.createElement('th')) 1.117 + .appendChild(document.createTextNode(isLocal ? 1.118 + 'Local candidate addr' : 1.119 + 'Remote candidate addr')); 1.120 + headerRow.appendChild(document.createElement('th')) 1.121 + .appendChild(document.createTextNode('Type')); 1.122 + return headerRow; 1.123 +} 1.124 + 1.125 +function buildEmptyCandPairTable() { 1.126 + var candPairTable = document.createElement('table'); 1.127 + candPairTable.appendChild(buildCandPairTableHeader()); 1.128 + return candPairTable; 1.129 +} 1.130 + 1.131 +function buildEmptyCandTable(local) { 1.132 + var candTable = document.createElement('table'); 1.133 + candTable.appendChild(buildCandTableHeader(local)); 1.134 + return candTable; 1.135 +} 1.136 + 1.137 +function round00(num) { 1.138 + return Math.round(num * 100) / 100; 1.139 +} 1.140 + 1.141 +function dumpAvStat(stat) { 1.142 + var div = document.createElement('div'); 1.143 + var statsString = ""; 1.144 + if (stat.mozAvSyncDelay !== undefined) { 1.145 + statsString += "A/V sync: " + stat.mozAvSyncDelay + " ms "; 1.146 + } 1.147 + if (stat.mozJitterBufferDelay !== undefined) { 1.148 + statsString += "Jitter-buffer delay: " + stat.mozJitterBufferDelay + " ms"; 1.149 + } 1.150 + div.appendChild(document.createTextNode(statsString)); 1.151 + return div; 1.152 +} 1.153 + 1.154 +function dumpRtpStat(stat, label) { 1.155 + var div = document.createElement('div'); 1.156 + var statsString = " " + label + new Date(stat.timestamp).toTimeString() + 1.157 + " " + stat.type + " SSRC: " + stat.ssrc; 1.158 + if (stat.packetsReceived !== undefined) { 1.159 + statsString += " Received: " + stat.packetsReceived + " packets"; 1.160 + if (stat.bytesReceived !== undefined) { 1.161 + statsString += " (" + round00(stat.bytesReceived/1024) + " Kb)"; 1.162 + } 1.163 + statsString += " Lost: " + stat.packetsLost + " Jitter: " + stat.jitter; 1.164 + if (stat.mozRtt !== undefined) { 1.165 + statsString += " RTT: " + stat.mozRtt + " ms"; 1.166 + } 1.167 + } else if (stat.packetsSent !== undefined) { 1.168 + statsString += " Sent: " + stat.packetsSent + " packets"; 1.169 + if (stat.bytesSent !== undefined) { 1.170 + statsString += " (" + round00(stat.bytesSent/1024) + " Kb)"; 1.171 + } 1.172 + } 1.173 + div.appendChild(document.createTextNode(statsString)); 1.174 + return div; 1.175 +} 1.176 + 1.177 +function buildPcDiv(stats, pcDivHeading) { 1.178 + var newPcDiv = document.createElement('div'); 1.179 + 1.180 + var heading = document.createElement('h3'); 1.181 + heading.appendChild(document.createTextNode(pcDivHeading)); 1.182 + newPcDiv.appendChild(heading); 1.183 + 1.184 + // First, ICE stats 1.185 + var iceHeading = document.createElement('h4'); 1.186 + iceHeading.appendChild(document.createTextNode("ICE statistics")); 1.187 + newPcDiv.appendChild(iceHeading); 1.188 + 1.189 + var iceTablesByComponent = {}; 1.190 + 1.191 + function getIceTables(componentId) { 1.192 + if (!iceTablesByComponent[componentId]) { 1.193 + iceTablesByComponent[componentId] = { 1.194 + candidatePairTable: buildEmptyCandPairTable(), 1.195 + localCandidateTable: buildEmptyCandTable(true), 1.196 + remoteCandidateTable: buildEmptyCandTable(false) 1.197 + }; 1.198 + } 1.199 + return iceTablesByComponent[componentId]; 1.200 + } 1.201 + 1.202 + // Candidates 1.203 + var candidateMap = {}; // Used later to speed up recording of candidate pairs 1.204 + 1.205 + if (stats.iceCandidateStats) { 1.206 + stats.iceCandidateStats.forEach(function(cand) { 1.207 + var tables = getIceTables(cand.componentId); 1.208 + 1.209 + candidateMap[cand.id] = cand; 1.210 + 1.211 + if (cand.type == "localcandidate") { 1.212 + tables.localCandidateTable.appendChild(buildCandTableRow(cand)); 1.213 + } else { 1.214 + tables.remoteCandidateTable.appendChild(buildCandTableRow(cand)); 1.215 + } 1.216 + }); 1.217 + } 1.218 + 1.219 + // Candidate pairs 1.220 + if (stats.iceCandidatePairStats) { 1.221 + stats.iceCandidatePairStats.forEach(function(candPair) { 1.222 + var candPairTable = 1.223 + getIceTables(candPair.componentId).candidatePairTable; 1.224 + candPairTable.appendChild( 1.225 + buildCandPairTableRow(candPair, 1.226 + candidateMap[candPair.localCandidateId], 1.227 + candidateMap[candPair.remoteCandidateId])); 1.228 + }); 1.229 + } 1.230 + 1.231 + // Now that tables are completely built, put them on the page. 1.232 + for (var cid in iceTablesByComponent) { 1.233 + if (iceTablesByComponent.hasOwnProperty(cid)) { 1.234 + var tables = iceTablesByComponent[cid]; 1.235 + newPcDiv.appendChild(document.createElement('h4')) 1.236 + .appendChild(document.createTextNode(cid)); 1.237 + newPcDiv.appendChild(tables.candidatePairTable); 1.238 + newPcDiv.appendChild(tables.localCandidateTable); 1.239 + newPcDiv.appendChild(tables.remoteCandidateTable); 1.240 + } 1.241 + } 1.242 + 1.243 + // end of ICE stats 1.244 + 1.245 + // Now, RTP stats 1.246 + var rtpHeading = document.createElement('h4'); 1.247 + rtpHeading.appendChild(document.createTextNode("RTP statistics")); 1.248 + newPcDiv.appendChild(rtpHeading); 1.249 + 1.250 + // Build map from id -> remote RTP stats (ie; stats obtained from RTCP 1.251 + // from the other end). This allows us to pair up local/remote stats for 1.252 + // the same stream more easily. 1.253 + var remoteRtpStatsMap = {}; 1.254 + 1.255 + var addRemoteStatToMap = function (rtpStat) { 1.256 + if (rtpStat.isRemote) { 1.257 + remoteRtpStatsMap[rtpStat.id] = rtpStat; 1.258 + } 1.259 + } 1.260 + 1.261 + if (stats.inboundRTPStreamStats) { 1.262 + stats.inboundRTPStreamStats.forEach(addRemoteStatToMap); 1.263 + } 1.264 + 1.265 + if (stats.outboundRTPStreamStats) { 1.266 + stats.outboundRTPStreamStats.forEach(addRemoteStatToMap); 1.267 + } 1.268 + 1.269 + var addRtpStatPairToDocument = function (rtpStat) { 1.270 + if (!rtpStat.isRemote) { 1.271 + newPcDiv.appendChild(document.createElement('h5')) 1.272 + .appendChild(document.createTextNode(rtpStat.id)); 1.273 + if (rtpStat.mozAvSyncDelay !== undefined || 1.274 + rtpStat.mozJitterBufferDelay !== undefined) { 1.275 + newPcDiv.appendChild(dumpAvStat(rtpStat)); 1.276 + } 1.277 + newPcDiv.appendChild(dumpRtpStat(rtpStat, "Local: ")); 1.278 + 1.279 + // Might not be receiving RTCP, so we have no idea what the 1.280 + // statistics look like from the perspective of the other end. 1.281 + if (rtpStat.remoteId) { 1.282 + var remoteRtpStat = remoteRtpStatsMap[rtpStat.remoteId]; 1.283 + newPcDiv.appendChild(dumpRtpStat(remoteRtpStat, "Remote: ")); 1.284 + } 1.285 + } 1.286 + } 1.287 + 1.288 + if (stats.outboundRTPStreamStats) { 1.289 + stats.outboundRTPStreamStats.forEach(addRtpStatPairToDocument); 1.290 + } 1.291 + 1.292 + if (stats.inboundRTPStreamStats) { 1.293 + stats.inboundRTPStreamStats.forEach(addRtpStatPairToDocument); 1.294 + } 1.295 + 1.296 + return newPcDiv; 1.297 +} 1.298 + 1.299 +function displayStats(globalReport) { 1.300 + console.log("Got stats callback."); 1.301 + globalReport.reports.forEach(function (report) { 1.302 + var pcDivHeading = 'PeerConnection:' + report.pcid; 1.303 + 1.304 + var pcDiv = document.getElementById(pcDivHeading); 1.305 + var newPcDiv = buildPcDiv(report, pcDivHeading); 1.306 + newPcDiv.id = pcDivHeading; 1.307 + 1.308 + if (!pcDiv) { 1.309 + document.getElementById('stats').appendChild(newPcDiv); 1.310 + } else { 1.311 + document.getElementById('stats').replaceChild(newPcDiv, pcDiv); 1.312 + } 1.313 + }); 1.314 + 1.315 + globalReport.errors.forEach(function (error) { 1.316 + var pcDivHeading = 'PeerConnection:' + error.pcid; 1.317 + 1.318 + var pcDiv = document.getElementById(pcDivHeading); 1.319 + var newPcDiv = buildPcDiv(error, pcDivHeading); 1.320 + newPcDiv.id = pcDivHeading; 1.321 + 1.322 + if (pcDiv) { 1.323 + document.getElementById('stats').replaceChild(newPcDiv, pcDiv); 1.324 + } else { 1.325 + document.getElementById('stats').appendChild(newPcDiv); 1.326 + } 1.327 + }); 1.328 +} 1.329 + 1.330 + </script> 1.331 + 1.332 + <body id="body" onload="WebrtcGlobalInformation.getAllStats(displayStats)"> 1.333 + <div id="stats"> 1.334 + </div> 1.335 + <button onclick="WebrtcGlobalInformation.getLogging('', displayLogs)"> 1.336 + Show/refresh logging 1.337 + </button> 1.338 + <div id="logs"> 1.339 + </div> 1.340 + </body> 1.341 +</html> 1.342 +<!-- vim: softtabstop=2:shiftwidth=2:expandtab 1.343 +-->