webrtc_m130/webrtc/tools/loopback_test/loopback_test.html
andresp@webrtc.org 44eb87e6dd Tool to establish a loopback call via apprtc turn server.
For now the test keeps track of video bandwidth estimation and plots it
using google visualization libraries after the test is concluded.
There is also scripts to run a test and record the tcpdump.

BUG=3037
R=hta@webrtc.org, phoglund@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/9729004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5707 4adac7df-926f-26a2-2b94-8c16560cd09d
2014-03-17 14:23:22 +00:00

221 lines
6.6 KiB
HTML

<!DOCTYPE html>
<!--
This page was created to help debug and study webrtc issues such as
bandwidth estimation problems. It allows one to easily launch a test
case that establishs a connection between 2 peer connections
-->
<html>
<head>
<title>Loopback test</title>
<!-- In order to plot graphs, this tools uses google visualization API which is
loaded via goog.load provided by google api. -->
<script src="//www.google.com/jsapi"></script>
<!-- This file is included to allow loopback_test.js instantiate a
RTCPeerConnection on a browser and version agnostic way. -->
<script src="adapter.js"></script>
<!-- Provides class StatTracker used by loopback_test.js to keep track of
RTCPeerConnection stats -->
<script src="stat_tracker.js"></script>
<!-- Provides LoopbackTest class which has the core logic for the test itself.
Such as: create 2 peer connections, establish a call, filter turn
candidates, constraint video bitrate etc.
-->
<script src="loopback_test.js"></script>
<style>
#chart {
height: 400px;
}
#control-range {
height: 100px;
}
</style>
</head>
<body>
<div id="test-launcher">
<p>Duration (s): <input id="duration" type="text"></p>
<p>Max video bitrate (kbps): <input id="max-video-bitrate" type="text"></p>
<p>Force TURN: <input id="force-turn" type="checkbox" checked></p>
<p><input id="launcher-button" type="button" value="Run test">
<div id="test-status" style="display:none"></div>
<div id="dashboard">
<div id="control-category"></div>
<div id="chart"></div>
<div id="control-range"></div>
</div>
</div>
<script>
google.load('visualization', '1.0', {'packages':['controls']});
var durationInput = document.getElementById('duration');
var maxVideoBitrateInput = document.getElementById('max-video-bitrate');
var forceTurnInput = document.getElementById('force-turn');
var launcherButton = document.getElementById('launcher-button');
var autoModeInput = document.createElement('input');
var testStatus = document.getElementById('test-status');
launcherButton.onclick = start;
// Load parameters from the url if present. This allows one to link to
// a specific test configuration and is used to automatically pass parameters
// for scripts such as record-test.sh
function getURLParameter(name, default_value) {
var search =
RegExp('(^\\?|&)' + name + '=' + '(.+?)(&|$)').exec(location.search);
if (search)
return decodeURI(search[2]);
else
return default_value;
}
durationInput.value = getURLParameter('duration', 10);
maxVideoBitrateInput.value = getURLParameter('max-video-bitrate', 2000);
forceTurnInput.checked = (getURLParameter('force-turn', 'true') === 'true');
autoModeInput.checked = (getURLParameter('auto-mode', 'false') === 'true');
if (autoModeInput.checked) start();
function start() {
var durationMs = parseInt(durationInput.value) * 1000;
var maxVideoBitrateKbps = parseInt(maxVideoBitrateInput.value);
var forceTurn = forceTurnInput.checked;
var autoClose = autoModeInput.checked;
var updateStatusInterval;
var testFinished = false;
function updateStatus() {
if (testFinished) {
testStatus.innerHTML = 'Test finished';
if (updateStatusInterval) {
clearInterval(updateStatusInterval);
updateStatusInterval = null;
}
} else {
if (!updateStatusInterval) {
updateStatusInterval = setInterval(updateStatus, 1000);
testStatus.innerHTML = 'Running';
}
testStatus.innerHTML += '.';
}
}
if (!(isFinite(maxVideoBitrateKbps) && maxVideoBitrateKbps > 0)) {
// TODO(andresp): Get a better way to show errors than alert.
alert("Invalid max video bitrate");
return;
}
if (!(isFinite(durationMs) && durationMs > 0)) {
alert("Invalid duration");
return;
}
durationInput.disabled = true;
forceTurnInput.disabled = true;
maxVideoBitrateInput.disabled = true;
launcherButton.style.display = 'none';
testStatus.style.display = 'block';
getUserMedia({audio:true, video:true},
gotStream, function() {});
function gotStream(stream) {
updateStatus();
var test = new LoopbackTest(stream, durationMs, forceTurn,
maxVideoBitrateKbps);
test.run(onTestFinished.bind(test));
}
function onTestFinished() {
testFinished = true;
updateStatus();
if (autoClose) {
window.close();
} else {
plotStats(this.getResults());
}
}
}
function plotStats(data) {
var dashboard = new google.visualization.Dashboard(
document.getElementById('dashboard'));
var chart = new google.visualization.ChartWrapper({
'containerId': 'chart',
'chartType': 'LineChart',
'options': { 'pointSize': 0, 'lineWidth': 1, 'interpolateNulls': true },
});
var rangeFilter = new google.visualization.ControlWrapper({
'controlType': 'ChartRangeFilter',
'containerId': 'control-range',
'options': {
'filterColumnIndex': 0,
'ui': {
'chartType': 'ScatterChart',
'chartOptions': {
'hAxis': {'baselineColor': 'none'}
},
'chartView': {
'columns': [0, 1]
},
'minRangeSize': 1000 // 1 second
}
},
});
// Create a table with the columns of the dataset.
var columnsTable = new google.visualization.DataTable();
columnsTable.addColumn('number', 'columnIndex');
columnsTable.addColumn('string', 'columnLabel');
var initState = {selectedValues: []};
for (var i = 1; i < data.getNumberOfColumns(); i++) {
columnsTable.addRow([i, data.getColumnLabel(i)]);
initState.selectedValues.push(data.getColumnLabel(i));
}
var columnFilter = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'control-category',
dataTable: columnsTable,
options: {
filterColumnLabel: 'columnLabel',
ui: {
label: '',
allowNone: false,
selectedValuesLayout: 'aside'
}
},
state: initState
});
google.visualization.events.addListener(columnFilter, 'statechange',
function () {
var state = columnFilter.getState();
var row;
var columnIndices = [0];
for (var i = 0; i < state.selectedValues.length; i++) {
row = columnsTable.getFilteredRows([{
column: 1,
value: state.selectedValues[i]}])[0];
columnIndices.push(columnsTable.getValue(row, 0));
}
// Sort the indices into their original order
columnIndices.sort(function (a, b) { return (a - b); });
chart.setView({columns: columnIndices});
chart.draw();
});
columnFilter.draw();
dashboard.bind([rangeFilter], [chart]);
dashboard.draw(data);
}
</script>
</body>
</html>