summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/webrtc/tools/loopback_test/loopback_test.html
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/webrtc/tools/loopback_test/loopback_test.html')
-rw-r--r--chromium/third_party/webrtc/tools/loopback_test/loopback_test.html227
1 files changed, 227 insertions, 0 deletions
diff --git a/chromium/third_party/webrtc/tools/loopback_test/loopback_test.html b/chromium/third_party/webrtc/tools/loopback_test/loopback_test.html
new file mode 100644
index 00000000000..676fbe79c40
--- /dev/null
+++ b/chromium/third_party/webrtc/tools/loopback_test/loopback_test.html
@@ -0,0 +1,227 @@
+<!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>Peer connection constraints: <input id="pc-constraints" 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');
+var pcConstraintsInput = document.getElementById('pc-constraints');
+
+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');
+pcConstraintsInput.value = getURLParameter('pc-constraints', '');
+
+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 pcConstraints = pcConstraintsInput.value == "" ?
+ null : JSON.parse(pcConstraintsInput.value);
+
+ 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,
+ pcConstraints,
+ 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>