gecko/toolkit/content/aboutWebrtc.xhtml

321 lines
10 KiB
HTML

<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE html [
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> %htmlDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Webrtc Internals</title>
</head>
<script>
function displayLogs(logs) {
var logsDiv = document.getElementById('logs');
while (logsDiv.lastChild) {
logsDiv.removeChild(logsDiv.lastChild);
}
logsDiv.appendChild(document.createElement('h3'))
.appendChild(document.createTextNode('Logging:'));
logs.forEach(function(logLine){
logsDiv.appendChild(document.createElement('div'))
.appendChild(document.createTextNode(logLine));
});
}
function candidateTypeString(cand) {
if (cand.type == "localcandidate") {
if (cand.candidateType == "relayed") {
return cand.candidateType + '-' + cand.mozLocalTransport;
}
}
return cand.candidateType;
}
function candidateAddrString(cand) {
return cand.ipAddress + ':' +
cand.portNumber + '/' +
cand.transport + '(' +
candidateTypeString(cand) + ')';
}
function buildCandPairTableRow(candPair, localCand, remoteCand) {
var row = document.createElement('tr');
row.onclick = function() {
WebrtcGlobalInformation.getLogging("CAND-PAIR(" + row.id, displayLogs);
}
if (localCand) {
row.appendChild(document.createElement('td'))
.appendChild(document.createTextNode(candidateAddrString(localCand)));
} else {
row.appendChild(document.createElement('td'))
.appendChild(document.createTextNode(candPair.localCandidateId));
}
if (remoteCand) {
row.appendChild(document.createElement('td'))
.appendChild(document.createTextNode(candidateAddrString(remoteCand)));
} else {
row.appendChild(document.createElement('td'))
.appendChild(document.createTextNode(candPair.remoteCandidateId));
}
row.appendChild(document.createElement('td'))
.appendChild(document.createTextNode(candPair.state));
row.appendChild(document.createElement('td'))
.appendChild(document.createTextNode(candPair.mozPriority));
row.appendChild(document.createElement('td'))
.appendChild(document.createTextNode(candPair.nominated ? '*' : ''));
row.appendChild(document.createElement('td'))
.appendChild(document.createTextNode(candPair.selected ? '*' : ''));
return row;
}
function buildCandTableRow(cand) {
var row = document.createElement('tr');
row.appendChild(document.createElement('td'))
.appendChild(document.createTextNode(cand.ipAddress + ':' +
cand.portNumber + '/' +
cand.transport));
row.appendChild(document.createElement('td'))
.appendChild(document.createTextNode(candidateTypeString(cand)));
return row;
}
function buildCandPairTableHeader() {
var headerRow = document.createElement('tr');
headerRow.appendChild(document.createElement('th'))
.appendChild(document.createTextNode('Local candidate'));
headerRow.appendChild(document.createElement('th'))
.appendChild(document.createTextNode('Remote candidate'));
headerRow.appendChild(document.createElement('th'))
.appendChild(document.createTextNode('ICE State'));
headerRow.appendChild(document.createElement('th'))
.appendChild(document.createTextNode('Priority'));
headerRow.appendChild(document.createElement('th'))
.appendChild(document.createTextNode('Nominated'));
headerRow.appendChild(document.createElement('th'))
.appendChild(document.createTextNode('Selected'));
return headerRow;
}
function buildCandTableHeader(isLocal) {
var headerRow = document.createElement('tr');
headerRow.appendChild(document.createElement('th'))
.appendChild(document.createTextNode(isLocal ?
'Local candidate addr' :
'Remote candidate addr'));
headerRow.appendChild(document.createElement('th'))
.appendChild(document.createTextNode('Type'));
return headerRow;
}
function buildEmptyCandPairTable() {
var candPairTable = document.createElement('table');
candPairTable.appendChild(buildCandPairTableHeader());
return candPairTable;
}
function buildEmptyCandTable(local) {
var candTable = document.createElement('table');
candTable.appendChild(buildCandTableHeader(local));
return candTable;
}
function round00(num) {
return Math.round(num * 100) / 100;
}
function dumpStat(stat, label) {
var div = document.createElement('div');
var statsString = " " + label + new Date(stat.timestamp).toTimeString() +
" " + stat.type + " SSRC: " + stat.ssrc;
if (stat.packetsReceived !== undefined) {
statsString += " Received: " + stat.packetsReceived + " packets";
if (stat.bytesReceived !== undefined) {
statsString += " (" + round00(stat.bytesReceived/1024) + " Kb)";
}
statsString += " Jitter: " + stat.jitter + " Lost: " + stat.packetsLost;
} else if (stat.packetsSent !== undefined) {
statsString += " Sent: " + stat.packetsSent + " packets";
if (stat.bytesSent !== undefined) {
statsString += " (" + round00(stat.bytesSent/1024) + " Kb)";
}
}
div.appendChild(document.createTextNode(statsString));
return div;
}
function buildPcDiv(stats, pcDivHeading) {
var newPcDiv = document.createElement('div');
var heading = document.createElement('h3');
heading.appendChild(document.createTextNode(pcDivHeading));
newPcDiv.appendChild(heading);
// First, ICE stats
var iceHeading = document.createElement('h4');
iceHeading.appendChild(document.createTextNode("ICE statistics"));
newPcDiv.appendChild(iceHeading);
var iceTablesByComponent = {};
function getIceTables(componentId) {
if (!iceTablesByComponent[componentId]) {
iceTablesByComponent[componentId] = {
candidatePairTable: buildEmptyCandPairTable(),
localCandidateTable: buildEmptyCandTable(true),
remoteCandidateTable: buildEmptyCandTable(false)
};
}
return iceTablesByComponent[componentId];
}
// Candidates
var candidateMap = {}; // Used later to speed up recording of candidate pairs
if (stats.iceCandidateStats) {
stats.iceCandidateStats.forEach(function(cand) {
var tables = getIceTables(cand.componentId);
candidateMap[cand.id] = cand;
if (cand.type == "localcandidate") {
tables.localCandidateTable.appendChild(buildCandTableRow(cand));
} else {
tables.remoteCandidateTable.appendChild(buildCandTableRow(cand));
}
});
}
// Candidate pairs
if (stats.iceCandidatePairStats) {
stats.iceCandidatePairStats.forEach(function(candPair) {
var candPairTable =
getIceTables(candPair.componentId).candidatePairTable;
candPairTable.appendChild(
buildCandPairTableRow(candPair,
candidateMap[candPair.localCandidateId],
candidateMap[candPair.remoteCandidateId]));
});
}
// Now that tables are completely built, put them on the page.
for (var cid in iceTablesByComponent) {
if (iceTablesByComponent.hasOwnProperty(cid)) {
var tables = iceTablesByComponent[cid];
newPcDiv.appendChild(document.createElement('h4'))
.appendChild(document.createTextNode(cid));
newPcDiv.appendChild(tables.candidatePairTable);
newPcDiv.appendChild(tables.localCandidateTable);
newPcDiv.appendChild(tables.remoteCandidateTable);
}
}
// end of ICE stats
// Now, RTP stats
var rtpHeading = document.createElement('h4');
rtpHeading.appendChild(document.createTextNode("RTP statistics"));
newPcDiv.appendChild(rtpHeading);
// Build map from id -> remote RTP stats (ie; stats obtained from RTCP
// from the other end). This allows us to pair up local/remote stats for
// the same stream more easily.
var remoteRtpStatsMap = {};
var addRemoteStatToMap = function (rtpStat) {
if (rtpStat.isRemote) {
remoteRtpStatsMap[rtpStat.id] = rtpStat;
}
}
if (stats.inboundRTPStreamStats) {
stats.inboundRTPStreamStats.forEach(addRemoteStatToMap);
}
if (stats.outboundRTPStreamStats) {
stats.outboundRTPStreamStats.forEach(addRemoteStatToMap);
}
var addRtpStatPairToDocument = function (rtpStat) {
if (!rtpStat.isRemote) {
newPcDiv.appendChild(document.createElement('h5'))
.appendChild(document.createTextNode(rtpStat.id));
newPcDiv.appendChild(dumpStat(rtpStat, "Local: "));
// Might not be receiving RTCP, so we have no idea what the
// statistics look like from the perspective of the other end.
if (rtpStat.remoteId) {
var remoteRtpStat = remoteRtpStatsMap[rtpStat.remoteId];
newPcDiv.appendChild(dumpStat(remoteRtpStat, "Remote: "));
}
}
}
if (stats.outboundRTPStreamStats) {
stats.outboundRTPStreamStats.forEach(addRtpStatPairToDocument);
}
if (stats.inboundRTPStreamStats) {
stats.inboundRTPStreamStats.forEach(addRtpStatPairToDocument);
}
return newPcDiv;
}
function displayStats(globalReport) {
console.log("Got stats callback.");
globalReport.reports.forEach(function (report) {
var pcDivHeading = 'PeerConnection:' + report.pcid;
var pcDiv = document.getElementById(pcDivHeading);
var newPcDiv = buildPcDiv(report, pcDivHeading);
newPcDiv.id = pcDivHeading;
if (!pcDiv) {
document.getElementById('stats').appendChild(newPcDiv);
} else {
document.getElementById('stats').replaceChild(newPcDiv, pcDiv);
}
});
globalReport.errors.forEach(function (error) {
var pcDivHeading = 'PeerConnection:' + error.pcid;
var pcDiv = document.getElementById(pcDivHeading);
var newPcDiv = buildPcDiv(error, pcDivHeading);
newPcDiv.id = pcDivHeading;
if (pcDiv) {
document.getElementById('stats').replaceChild(newPcDiv, pcDiv);
} else {
document.getElementById('stats').appendChild(newPcDiv);
}
});
}
</script>
<body id="body" onload="WebrtcGlobalInformation.getAllStats(displayStats)">
<div id="stats">
</div>
<button onclick="WebrtcGlobalInformation.getLogging('', displayLogs)">
Show/refresh logging
</button>
<div id="logs">
</div>
</body>
</html>
<!-- vim: softtabstop=2:shiftwidth=2:expandtab
-->