Adding codec constraints page to webrtc.
Delete videoCall page to avoid duplication.
Bug: webrtc:653087
Change-Id: If44bed19c4323231e9a4348814f19c9694c17a36
Reviewed-on: https://chromium-review.googlesource.com/616770
Commit-Queue: Charu Jain <[email protected]>
Reviewed-by: Ned Nguyen <[email protected]>
Cr-Commit-Position: refs/heads/master@{#494835}
diff --git a/tools/perf/page_sets/update_webrtc_cases b/tools/perf/page_sets/update_webrtc_cases
index 01f55fe5..b76cd38f 100755
--- a/tools/perf/page_sets/update_webrtc_cases
+++ b/tools/perf/page_sets/update_webrtc_cases
@@ -21,16 +21,16 @@
'test-pages': {
'dirs': [
'src/canvas-capture',
+ 'src/codec_constraints',
'src/multiple-peerconnections',
'src/pause-play',
],
- 'revision': 'cbb12a3994692c63c9d885c95db0f67c5e3e3465',
+ 'revision': '9f0ff9343a38dbf16199a964a18d7411d940c601',
},
'samples': {
'dirs': [
'src/content/datachannel/datatransfer',
'src/content/getusermedia/resolution',
- 'src/content/peerconnection/constraints',
'src/content/peerconnection/audio',
],
'files': [
diff --git a/tools/perf/page_sets/webrtc_cases.py b/tools/perf/page_sets/webrtc_cases.py
index 66155b97..e462cb8 100644
--- a/tools/perf/page_sets/webrtc_cases.py
+++ b/tools/perf/page_sets/webrtc_cases.py
@@ -28,28 +28,6 @@
action_runner.Wait(10)
-class VideoCall(WebrtcPage):
- """Why: Sets up a local video-only WebRTC 720p call for 45 seconds."""
-
- def __init__(self, page_set, tags):
- super(VideoCall, self).__init__(
- url='file://webrtc_cases/constraints.html',
- name='720p_call_45s',
- page_set=page_set, tags=tags)
-
- def RunPageInteractions(self, action_runner):
- with action_runner.CreateInteraction('Action_Create_PeerConnection',
- repeatable=False):
- action_runner.ExecuteJavaScript('minWidthInput.value = 1280')
- action_runner.ExecuteJavaScript('maxWidthInput.value = 1280')
- action_runner.ExecuteJavaScript('minHeightInput.value = 720')
- action_runner.ExecuteJavaScript('maxHeightInput.value = 720')
- action_runner.ClickElement('button[id="getMedia"]')
- action_runner.Wait(2)
- action_runner.ClickElement('button[id="connect"]')
- action_runner.Wait(45)
-
-
class DataChannel(WebrtcPage):
"""Why: Transfer as much data as possible through a data channel in 10s."""
@@ -96,6 +74,26 @@
action_runner.Wait(10)
+class VideoCodecConstraints(WebrtcPage):
+ """Why: Sets up a video codec to a peer connection."""
+
+ def __init__(self, page_set, video_codec, tags):
+ super(VideoCodecConstraints, self).__init__(
+ url='file://webrtc_cases/codec_constraints.html',
+ name='codec_constraints_%s' % video_codec.lower(),
+ page_set=page_set, tags=tags)
+ self.video_codec = video_codec
+
+ def RunPageInteractions(self, action_runner):
+ with action_runner.CreateInteraction('Action_Codec_Constraints',
+ repeatable=False):
+ action_runner.ClickElement('input[id="%s"]' % self.video_codec)
+ action_runner.ClickElement('button[id="startButton"]')
+ action_runner.ClickElement('button[id="callButton"]')
+ action_runner.Wait(20)
+ action_runner.ClickElement('button[id="hangupButton"]')
+
+
class MultiplePeerConnections(WebrtcPage):
"""Why: Sets up several peer connections in the same page."""
@@ -143,9 +141,11 @@
self.AddStory(MultiplePeerConnections(self, tags=['stress']))
self.AddStory(DataChannel(self, tags=['datachannel']))
self.AddStory(GetUserMedia(self, tags=['getusermedia']))
- self.AddStory(VideoCall(self, tags=['peerconnection', 'smoothness']))
self.AddStory(CanvasCapturePeerConnection(self, tags=['smoothness']))
self.AddStory(AudioCall(self, 'OPUS', tags=['audio']))
self.AddStory(AudioCall(self, 'G772', tags=['audio']))
self.AddStory(AudioCall(self, 'PCMU', tags=['audio']))
self.AddStory(AudioCall(self, 'ISAC/1600', tags=['audio']))
+ self.AddStory(VideoCodecConstraints(self, 'H264', tags=['videoConstraints']))
+ self.AddStory(VideoCodecConstraints(self, 'VP8', tags=['videoConstraints']))
+ self.AddStory(VideoCodecConstraints(self, 'VP9', tags=['videoConstraints']))
diff --git a/tools/perf/page_sets/webrtc_cases/codec_constraints.html b/tools/perf/page_sets/webrtc_cases/codec_constraints.html
new file mode 100644
index 0000000..1e85c49
--- /dev/null
+++ b/tools/perf/page_sets/webrtc_cases/codec_constraints.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<!--
+ * Copyright 2017 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+-->
+<html>
+<head>
+
+
+ <base target="_blank">
+
+ <title>Video codec constraints</title>
+
+
+</head>
+
+<body>
+
+ <div id="container">
+
+ <div class="highlight">
+ <p>New codelab: <a href="https://codelabs.developers.google.com/codelabs/webrtc-web">Realtime communication with WebRTC</a></p>
+ </div>
+
+ <h1><a href="//webrtc.github.io/samples/" title="WebRTC samples homepage">WebRTC samples</a> <span>Peer connection with codec constraints</span></h1>
+
+ <video id="localVideo" autoplay muted></video>
+ <video id="remoteVideo" autoplay></video>
+
+ <div>
+ <h2>Video Codec Constraints</h2>
+ <input type="radio" id="H264" name="Codec" value="H264" checked>H264<br>
+ <input type="radio" id="VP8" name="Codec" value="VP8" checked>VP8<br>
+ <input type="radio" id="VP9" name="Codec" value="VP9" checked>VP9<br><br>
+ </div>
+ <div>
+ <button id="startButton">Start</button>
+ <button id="callButton">Call</button>
+ <button id="hangupButton">Hang Up</button>
+ </div>
+
+ <p>View the console to see logging. The <code>MediaStream</code> object <code>localStream</code>, and the <code>RTCPeerConnection</code> objects <code>pc1</code> and <code>pc2</code> are in global scope, so you can inspect them in the console as well.</p>
+
+ <p>For more information about RTCPeerConnection, see <a href="http://www.html5rocks.com/en/tutorials/webrtc/basics/" title="HTML5 Rocks article about WebRTC by Sam Dutton">Getting Started With WebRTC</a>.</p>
+
+
+ <a href="https://github.com/webrtc/samples/tree/gh-pages/src/content/peerconnection/codec_constraints" title="View source for this page on GitHub" id="viewSource">View source on GitHub</a>
+
+ </div>
+
+
+<script src="codec_constraints.js"></script>
+<script src="adapter.js"></script>
+<script src="common.js"></script>
+</body></html>
diff --git a/tools/perf/page_sets/webrtc_cases/codec_constraints.js b/tools/perf/page_sets/webrtc_cases/codec_constraints.js
new file mode 100644
index 0000000..1a1cf91
--- /dev/null
+++ b/tools/perf/page_sets/webrtc_cases/codec_constraints.js
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2017 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+'use strict';
+
+var startButton = document.getElementById('startButton');
+var callButton = document.getElementById('callButton');
+var hangupButton = document.getElementById('hangupButton');
+callButton.disabled = true;
+hangupButton.disabled = true;
+startButton.onclick = start;
+callButton.onclick = startTest;
+hangupButton.onclick = hangup;
+
+var startTime;
+var localVideo = document.getElementById('localVideo');
+var remoteVideo = document.getElementById('remoteVideo');
+
+function trace(arg) {
+ var now = (window.performance.now() / 1000).toFixed(3);
+ console.log(now + ': ', arg);
+}
+
+function getSelectedVideoCodec() {
+ var codec;
+ if (document.getElementById('H264').checked) {
+ codec = document.getElementById('H264').value;
+ } else if (document.getElementById('VP8').checked) {
+ codec = document.getElementById('VP8').value;
+ } else {
+ codec = document.getElementById('VP9').value;
+ }
+ return codec;
+}
+
+function Failure(message) {
+ this.message = message;
+ this.name = 'Failure';
+}
+
+localVideo.addEventListener('loadedmetadata', function() {
+ trace('Local video videoWidth: ' + this.videoWidth +
+ 'px, videoHeight: ' + this.videoHeight + 'px');
+});
+
+remoteVideo.addEventListener('loadedmetadata', function() {
+ trace('Remote video videoWidth: ' + this.videoWidth +
+ 'px, videoHeight: ' + this.videoHeight + 'px');
+});
+
+remoteVideo.onresize = function() {
+ trace('Remote video size changed to ' +
+ remoteVideo.videoWidth + 'x' + remoteVideo.videoHeight);
+ // We'll use the first onsize callback as an indication that video has started
+ // playing out.
+ if (startTime) {
+ var elapsedTime = window.performance.now() - startTime;
+ trace('Setup time: ' + elapsedTime.toFixed(3) + 'ms');
+ startTime = null;
+ }
+};
+
+var localStream;
+var pc1;
+var pc2;
+var offerOptions = {
+ offerToReceiveAudio: 1,
+ offerToReceiveVideo: 1
+};
+
+function getName(pc) {
+ return (pc === pc1) ? 'pc1' : 'pc2';
+}
+
+function getOtherPc(pc) {
+ return (pc === pc1) ? pc2 : pc1;
+}
+
+function gotStream(stream) {
+ trace('Received local stream');
+ localVideo.srcObject = stream;
+ localStream = stream;
+ callButton.disabled = false;
+}
+
+function start() {
+ trace('Requesting local stream');
+ startButton.disabled = true;
+ navigator.mediaDevices.getUserMedia({
+ audio: true,
+ video: {
+ width: {exact: 1280},
+ height: {exact: 720},
+ },
+ })
+ .then(gotStream)
+ .catch(function(e) {
+ alert('getUserMedia() error: ' + e.name);
+ });
+}
+
+function call() {
+ callButton.disabled = true;
+ hangupButton.disabled = false;
+ trace('Starting call');
+ startTime = window.performance.now();
+ var videoTracks = localStream.getVideoTracks();
+ var audioTracks = localStream.getAudioTracks();
+ if (videoTracks.length > 0) {
+ trace('Using video device: ' + videoTracks[0].label);
+ }
+ if (audioTracks.length > 0) {
+ trace('Using audio device: ' + audioTracks[0].label);
+ }
+ var servers = null;
+ pc1 = new RTCPeerConnection(servers);
+ trace('Created local peer connection object pc1');
+ pc1.onicecandidate = function(e) {
+ onIceCandidate(pc1, e);
+ };
+ pc2 = new RTCPeerConnection(servers);
+ trace('Created remote peer connection object pc2');
+ pc2.onicecandidate = function(e) {
+ onIceCandidate(pc2, e);
+ };
+ pc1.oniceconnectionstatechange = function(e) {
+ onIceStateChange(pc1, e);
+ };
+ pc2.oniceconnectionstatechange = function(e) {
+ onIceStateChange(pc2, e);
+ };
+ pc2.ontrack = gotRemoteStream;
+
+ localStream.getTracks().forEach(
+ function(track) {
+ pc1.addTrack(
+ track,
+ localStream
+ );
+ }
+ );
+ trace('Added local stream to pc1');
+
+ trace('pc1 createOffer start');
+ pc1.createOffer(
+ offerOptions
+ ).then(
+ onCreateOfferSuccess,
+ onCreateSessionDescriptionError
+ );
+}
+
+function onCreateSessionDescriptionError(error) {
+ trace('Failed to create session description: ' + error.toString());
+}
+
+/**
+ * See |setSdpDefaultCodec|.
+ */
+function setSdpDefaultVideoCodec(sdp, codec, preferHwCodec) {
+ return setSdpDefaultCodec(sdp, 'video', codec, preferHwCodec);
+}
+
+/**
+ * Returns a modified version of |sdp| where the |codec| has been promoted to be
+ * the default codec, i.e. the codec whose ID is first in the list of codecs on
+ * the 'm=|type|' line, where |type| is 'audio' or 'video'. If |preferHwCodec|
+ * is true, it will select the last codec with the given name, and if false, it
+ * will select the first codec with the given name, because HW codecs are listed
+ * after SW codecs in the SDP list.
+ * @private
+ */
+function setSdpDefaultCodec(sdp, type, codec, preferHwCodec) {
+ var sdpLines = splitSdpLines(sdp);
+
+ // Find codec ID, e.g. 100 for 'VP8' if 'a=rtpmap:100 VP8/9000'.
+ var codecId = findRtpmapId(sdpLines, codec, preferHwCodec);
+ if (codecId === null) {
+ throw new Failure('setSdpDefaultCodec',
+ 'Unknown ID for |codec| = \'' + codec + '\'.');
+ }
+
+ // Find 'm=|type|' line, e.g. 'm=video 9 UDP/TLS/RTP/SAVPF 100 101 107 116'.
+ var mLineNo = findLine(sdpLines, 'm=' + type);
+ if (mLineNo === null) {
+ throw new Failure('setSdpDefaultCodec',
+ '\'m=' + type + '\' line missing from |sdp|.');
+ }
+
+ // Modify video line to use the desired codec as the default.
+ sdpLines[mLineNo] = setMLineDefaultCodec(sdpLines[mLineNo], codecId);
+ return mergeSdpLines(sdpLines);
+}
+
+/**
+ * Searches through all |sdpLines| for the 'a=rtpmap:' line for the codec of
+ * the specified name, returning its ID as an int if found, or null otherwise.
+ * |codec| is the case-sensitive name of the codec. If |lastInstance|
+ * is true, it will return the last such ID, and if false, it will return the
+ * first such ID.
+ * For example, if |sdpLines| contains 'a=rtpmap:100 VP8/9000' and |codec| is
+ * 'VP8', this function returns 100.
+ * @private
+ */
+function findRtpmapId(sdpLines, codec, lastInstance) {
+ var lineNo = findRtpmapLine(sdpLines, codec, lastInstance);
+ if (lineNo === null) {
+ return null;
+ }
+ // Parse <id> from 'a=rtpmap:<id> <codec>/<rate>'.
+ var id = sdpLines[lineNo].substring(9, sdpLines[lineNo].indexOf(' '));
+ return parseInt(id);
+}
+
+/**
+ * Finds a 'a=rtpmap:' line from |sdpLines| that contains |contains| and returns
+ * its line index, or null if no such line was found. |contains| may be the
+ * codec ID, codec name or bitrate. If |lastInstance| is true, it will return
+ * the last such line index, and if false, it will return the first such line
+ * index.
+ * An 'a=rtpmap:' line looks like this: 'a=rtpmap:<id> <codec>/<rate>'.
+ */
+function findRtpmapLine(sdpLines, contains, lastInstance) {
+ if (lastInstance === true) {
+ for (var i = sdpLines.length - 1; i >= 0 ; i--) {
+ if (isRtpmapLine(sdpLines[i], contains)) {
+ return i;
+ }
+ }
+ } else {
+ for (i = 0; i < sdpLines.length; i++) {
+ if (isRtpmapLine(sdpLines[i], contains)) {
+ return i;
+ }
+ }
+ }
+ return null;
+}
+
+/**
+ * Returns true if |sdpLine| contains |contains| and is of pattern
+ * 'a=rtpmap:<id> <codec>/<rate>'.
+ */
+function isRtpmapLine(sdpLine, contains) {
+ // Is 'a=rtpmap:' line containing |contains| string?
+ if (sdpLine.startsWith('a=rtpmap:') &&
+ sdpLine.indexOf(contains) !== -1) {
+ // Expecting pattern 'a=rtpmap:<id> <codec>/<rate>'.
+ var pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+');
+ if (!sdpLine.match(pattern)) {
+ throw new Failure('isRtpmapLine', 'Unexpected "a=rtpmap:" pattern.');
+ }
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Returns a modified version of |mLine| that has |codecId| first in the list of
+ * codec IDs. For example, setMLineDefaultCodec(
+ * 'm=video 9 UDP/TLS/RTP/SAVPF 100 101 107 116 117 96', 107)
+ * Returns:
+ * 'm=video 9 UDP/TLS/RTP/SAVPF 107 100 101 116 117 96'
+ * @private
+ */
+function setMLineDefaultCodec(mLine, codecId) {
+ var elements = mLine.split(' ');
+
+ // Copy first three elements, codec order starts on fourth.
+ var newLine = elements.slice(0, 3);
+
+ // Put target |codecId| first and copy the rest.
+ newLine.push(codecId);
+ for (var i = 3; i < elements.length; i++) {
+ if (elements[i] !== codecId) {
+ newLine.push(elements[i]);
+ }
+ }
+
+ return newLine.join(' ');
+}
+
+/** @private */
+function splitSdpLines(sdp) {
+ return sdp.split('\r\n');
+}
+
+/** @private */
+function mergeSdpLines(sdpLines) {
+ return sdpLines.join('\r\n');
+}
+
+/** @private */
+function findLine(lines, lineStartsWith, startingLine = 0) {
+ for (var i = startingLine; i < lines.length; i++) {
+ if (lines[i].startsWith(lineStartsWith)) {
+ return i;
+ }
+ }
+ return null;
+}
+
+function onCreateOfferSuccess(desc) {
+ var videoCodec = getSelectedVideoCodec();
+ desc.sdp = setSdpDefaultVideoCodec(desc.sdp, videoCodec, videoCodec);
+ trace('Offer from pc1\n' + desc.sdp);
+ trace('Ok-' + JSON.stringify(desc));
+ trace('pc1 setLocalDescription start');
+ pc1.setLocalDescription(desc).then(
+ function() {
+ onSetLocalSuccess(pc1);
+ },
+ onSetSessionDescriptionError
+ );
+ trace('pc2 setRemoteDescription start');
+ pc2.setRemoteDescription(desc).then(
+ function() {
+ onSetRemoteSuccess(pc2);
+ },
+ onSetSessionDescriptionError
+ );
+ trace('pc2 createAnswer start');
+ // Since the 'remote' side has no media stream we need
+ // to pass in the right constraints in order for it to
+ // accept the incoming offer of audio and video.
+ pc2.createAnswer().then(
+ onCreateAnswerSuccess,
+ onCreateSessionDescriptionError
+ );
+}
+
+function onSetLocalSuccess(pc) {
+ trace(getName(pc) + ' setLocalDescription complete');
+}
+
+function onSetRemoteSuccess(pc) {
+ trace(getName(pc) + ' setRemoteDescription complete');
+}
+
+function onSetSessionDescriptionError(error) {
+ trace('Failed to set session description: ' + error.toString());
+}
+
+function startTest() {
+ call();
+ setInterval(() => {
+ pc1.getStats((response) => {
+ trace(response);
+ });
+ }, 10 * 1000);
+}
+
+function gotRemoteStream(e) {
+ if (remoteVideo.srcObject !== e.streams[0]) {
+ remoteVideo.srcObject = e.streams[0];
+ trace('pc2 received remote stream');
+ }
+}
+
+function onCreateAnswerSuccess(desc) {
+ trace('Answer from pc2:\n' + desc.sdp);
+ trace('pc2 setLocalDescription start');
+ pc2.setLocalDescription(desc).then(
+ function() {
+ onSetLocalSuccess(pc2);
+ },
+ onSetSessionDescriptionError
+ );
+ trace('pc1 setRemoteDescription start');
+ pc1.setRemoteDescription(desc).then(
+ function() {
+ onSetRemoteSuccess(pc1);
+ },
+ onSetSessionDescriptionError
+ );
+}
+
+function onIceCandidate(pc, event) {
+ getOtherPc(pc).addIceCandidate(event.candidate)
+ .then(
+ function() {
+ onAddIceCandidateSuccess(pc);
+ },
+ function(err) {
+ onAddIceCandidateError(pc, err);
+ }
+ );
+ trace(getName(pc) + ' ICE candidate: \n' + (event.candidate ?
+ event.candidate.candidate : '(null)'));
+}
+
+function onAddIceCandidateSuccess(pc) {
+ trace(getName(pc) + ' addIceCandidate success');
+}
+
+function onAddIceCandidateError(pc, error) {
+ trace(getName(pc) + ' failed to add ICE Candidate: ' + error.toString());
+}
+
+function onIceStateChange(pc, event) {
+ if (pc) {
+ trace(getName(pc) + ' ICE state: ' + pc.iceConnectionState);
+ console.log('ICE state change event: ', event);
+ }
+}
+
+function hangup() {
+ trace('Ending call');
+ pc1.close();
+ pc2.close();
+ pc1 = null;
+ pc2 = null;
+ hangupButton.disabled = true;
+ callButton.disabled = false;
+}
diff --git a/tools/perf/page_sets/webrtc_cases/constraints.html b/tools/perf/page_sets/webrtc_cases/constraints.html
deleted file mode 100644
index e094ae6da..0000000
--- a/tools/perf/page_sets/webrtc_cases/constraints.html
+++ /dev/null
@@ -1,99 +0,0 @@
-<!DOCTYPE html>
-<!--
- * Copyright 2017 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
--->
-<html>
-<head>
-
-
- <base target="_blank">
-
- <title>Constraints and statistics</title>
-
-
-</head>
-
-<body>
-
- <div id="container">
-
- <h1><a href="//webrtc.github.io/samples/" title="WebRTC samples homepage">WebRTC samples</a> <span>Constraints & statistics</span></h1>
-
- <section id="blurb">
- <p>This demo shows ways to use constraints and statistics in WebRTC applications.</p>
- <p>Set camera constraints, and click <strong>Get media</strong> to (re)open the camera with these included. Click <strong>Connect</strong> to create a (local) peer connection. The RTCPeerConnection objects <code>localPeerConnection</code> and <code>remotePeerConnection</code> can be inspected from the console.</p>
- <p>Setting a value to zero will remove that constraint. </p>
- <p>The lefthand video shows the output of <code>getUserMedia()</code>; on the right is the video after being passed through the peer connection. The transmission bitrate is displayed below the righthand video.</p>
- </section>
-
- <div>
- <button id="getMedia">Get media</button>
- <button id="connect" disabled>Connect</button>
- <button id="hangup" disabled>Hang Up</button>
- </div>
-
-
- <section id="constraints">
- <div id="getUserMedia">
- <div class="input">
- <h2>Camera constraints</h2>
- <div id="minWidth">
- <label>Min width <span>300</span>px:</label>
- <input type="range" min="0" max="1920" value="300">
- </div>
- <div id="maxWidth">
- <label>Max width <span>640</span>px:</label>
- <input type="range" min="0" max="1920" value="640">
- </div>
- <div id="minHeight">
- <label>Min height <span>200</span>px:</label>
- <input type="range" min="0" max="1080" value="200">
- </div>
- <div id="maxHeight">
- <label>Max height <span>480</span>px:</label>
- <input type="range" min="0" max="1080" value="480">
- </div>
- <div id="minFramerate">
- <label>Min frameRate <span>0</span>fps:</label>
- <input type="range" min="0" max="60" value="0">
- </div>
- <div id="maxFramerate">
- <label>Max frameRate <span>0</span>fps:</label>
- <input type="range" min="0" max="60" value="0">
- </div>
- </div>
- <div id="getUserMediaConstraints" class="output"></div>
- </div>
-
- </section>
-
- <section id="video">
- <div id="localVideo">
- <video autoplay muted></video>
- <div></div>
- </div>
- <div id="remoteVideo">
- <video autoplay muted></video>
- <div></div>
- <div id="bitrate"></div>
- <div id="peer"></div>
- </div>
- </section>
-
- <section id="statistics">
- <div id="senderStats"></div>
- <div id="receiverStats"></div>
- </section>
-
- <a href="https://github.com/webrtc/samples/tree/gh-pages/src/content/peerconnection/constraints" title="View source for this page on GitHub" id="viewSource">View source on GitHub</a>
-
- </div>
-
-
-
-<script src="constraints.js"></script>
-<script src="adapter.js"></script>
-<script src="common.js"></script>
-</body></html>
diff --git a/tools/perf/page_sets/webrtc_cases/constraints.js b/tools/perf/page_sets/webrtc_cases/constraints.js
deleted file mode 100644
index d19d2123..0000000
--- a/tools/perf/page_sets/webrtc_cases/constraints.js
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright 2017 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-'use strict';
-
-var getMediaButton = document.querySelector('button#getMedia');
-var connectButton = document.querySelector('button#connect');
-var hangupButton = document.querySelector('button#hangup');
-
-getMediaButton.onclick = getMedia;
-connectButton.onclick = createPeerConnection;
-hangupButton.onclick = hangup;
-
-var minWidthInput = document.querySelector('div#minWidth input');
-var maxWidthInput = document.querySelector('div#maxWidth input');
-var minHeightInput = document.querySelector('div#minHeight input');
-var maxHeightInput = document.querySelector('div#maxHeight input');
-var minFramerateInput = document.querySelector('div#minFramerate input');
-var maxFramerateInput = document.querySelector('div#maxFramerate input');
-
-minWidthInput.onchange = maxWidthInput.onchange =
- minHeightInput.onchange = maxHeightInput.onchange =
- minFramerateInput.onchange = maxFramerateInput.onchange = displayRangeValue;
-
-var getUserMediaConstraintsDiv =
- document.querySelector('div#getUserMediaConstraints');
-var bitrateDiv = document.querySelector('div#bitrate');
-var peerDiv = document.querySelector('div#peer');
-var senderStatsDiv = document.querySelector('div#senderStats');
-var receiverStatsDiv = document.querySelector('div#receiverStats');
-
-var localVideo = document.querySelector('div#localVideo video');
-var remoteVideo = document.querySelector('div#remoteVideo video');
-var localVideoStatsDiv = document.querySelector('div#localVideo div');
-var remoteVideoStatsDiv = document.querySelector('div#remoteVideo div');
-
-var localPeerConnection;
-var remotePeerConnection;
-var localStream;
-var bytesPrev;
-var timestampPrev;
-
-main();
-
-function main() {
- displayGetUserMediaConstraints();
-}
-
-function hangup() {
- trace('Ending call');
- localPeerConnection.close();
- remotePeerConnection.close();
- localPeerConnection = null;
- remotePeerConnection = null;
-
- localStream.getTracks().forEach(function(track) {
- track.stop();
- });
- localStream = null;
-
- hangupButton.disabled = true;
- getMediaButton.disabled = false;
-}
-
-function getMedia() {
- getMediaButton.disabled = true;
- if (localStream) {
- localStream.getTracks().forEach(function(track) {
- track.stop();
- });
- var videoTracks = localStream.getVideoTracks();
- for (var i = 0; i !== videoTracks.length; ++i) {
- videoTracks[i].stop();
- }
- }
- navigator.mediaDevices.getUserMedia(getUserMediaConstraints())
- .then(gotStream)
- .catch(function(e) {
- var message = 'getUserMedia error: ' + e.name + '\n' +
- 'PermissionDeniedError may mean invalid constraints.';
- alert(message);
- console.log(message);
- getMediaButton.disabled = false;
- });
-}
-
-function gotStream(stream) {
- connectButton.disabled = false;
- console.log('GetUserMedia succeeded');
- localStream = stream;
- localVideo.srcObject = stream;
-}
-
-function getUserMediaConstraints() {
- var constraints = {};
- constraints.audio = true;
- constraints.video = {};
- if (minWidthInput.value !== '0') {
- constraints.video.width = {};
- constraints.video.width.min = minWidthInput.value;
- }
- if (maxWidthInput.value !== '0') {
- constraints.video.width = constraints.video.width || {};
- constraints.video.width.max = maxWidthInput.value;
- }
- if (minHeightInput.value !== '0') {
- constraints.video.height = {};
- constraints.video.height.min = minHeightInput.value;
- }
- if (maxHeightInput.value !== '0') {
- constraints.video.height = constraints.video.height || {};
- constraints.video.height.max = maxHeightInput.value;
- }
- if (minFramerateInput.value !== '0') {
- constraints.video.frameRate = {};
- constraints.video.frameRate.min = minFramerateInput.value;
- }
- if (maxFramerateInput.value !== '0') {
- constraints.video.frameRate = constraints.video.frameRate || {};
- constraints.video.frameRate.max = maxFramerateInput.value;
- }
-
- return constraints;
-}
-
-function displayGetUserMediaConstraints() {
- var constraints = getUserMediaConstraints();
- console.log('getUserMedia constraints', constraints);
- getUserMediaConstraintsDiv.textContent =
- JSON.stringify(constraints, null, ' ');
-}
-
-function createPeerConnection() {
- connectButton.disabled = true;
- hangupButton.disabled = false;
-
- bytesPrev = 0;
- timestampPrev = 0;
- localPeerConnection = new RTCPeerConnection(null);
- remotePeerConnection = new RTCPeerConnection(null);
- localStream.getTracks().forEach(
- function(track) {
- localPeerConnection.addTrack(
- track,
- localStream
- );
- }
- );
- console.log('localPeerConnection creating offer');
- localPeerConnection.onnegotiationeeded = function() {
- console.log('Negotiation needed - localPeerConnection');
- };
- remotePeerConnection.onnegotiationeeded = function() {
- console.log('Negotiation needed - remotePeerConnection');
- };
- localPeerConnection.onicecandidate = function(e) {
- console.log('Candidate localPeerConnection');
- remotePeerConnection.addIceCandidate(e.candidate)
- .then(
- onAddIceCandidateSuccess,
- onAddIceCandidateError
- );
- };
- remotePeerConnection.onicecandidate = function(e) {
- console.log('Candidate remotePeerConnection');
- localPeerConnection.addIceCandidate(e.candidate)
- .then(
- onAddIceCandidateSuccess,
- onAddIceCandidateError
- );
- };
- remotePeerConnection.ontrack = function(e) {
- if (remoteVideo.srcObject !== e.streams[0]) {
- console.log('remotePeerConnection got stream');
- remoteVideo.srcObject = e.streams[0];
- }
- };
- localPeerConnection.createOffer().then(
- function(desc) {
- console.log('localPeerConnection offering');
- localPeerConnection.setLocalDescription(desc);
- remotePeerConnection.setRemoteDescription(desc);
- remotePeerConnection.createAnswer().then(
- function(desc2) {
- console.log('remotePeerConnection answering');
- remotePeerConnection.setLocalDescription(desc2);
- localPeerConnection.setRemoteDescription(desc2);
- },
- function(err) {
- console.log(err);
- }
- );
- },
- function(err) {
- console.log(err);
- }
- );
-}
-
-function onAddIceCandidateSuccess() {
- trace('AddIceCandidate success.');
-}
-
-function onAddIceCandidateError(error) {
- trace('Failed to add Ice Candidate: ' + error.toString());
-}
-
-// Display statistics
-setInterval(function() {
- if (remotePeerConnection && remotePeerConnection.getRemoteStreams()[0]) {
- remotePeerConnection.getStats(null)
- .then(function(results) {
- var statsString = dumpStats(results);
- receiverStatsDiv.innerHTML = '<h2>Receiver stats</h2>' + statsString;
- // calculate video bitrate
- results.forEach(function(report) {
- var now = report.timestamp;
-
- var bitrate;
- if (report.type === 'inboundrtp' && report.mediaType === 'video') {
- // firefox calculates the bitrate for us
- // https://bugzilla.mozilla.org/show_bug.cgi?id=951496
- bitrate = Math.floor(report.bitrateMean / 1024);
- } else if (report.type === 'ssrc' && report.bytesReceived &&
- report.googFrameHeightReceived) {
- // chrome does not so we need to do it ourselves
- var bytes = report.bytesReceived;
- if (timestampPrev) {
- bitrate = 8 * (bytes - bytesPrev) / (now - timestampPrev);
- bitrate = Math.floor(bitrate);
- }
- bytesPrev = bytes;
- timestampPrev = now;
- }
- if (bitrate) {
- bitrate += ' kbits/sec';
- bitrateDiv.innerHTML = '<strong>Bitrate:</strong> ' + bitrate;
- }
- });
-
- // figure out the peer's ip
- var activeCandidatePair = null;
- var remoteCandidate = null;
-
- // Search for the candidate pair, spec-way first.
- results.forEach(function(report) {
- if (report.type === 'transport') {
- activeCandidatePair = results.get(report.selectedCandidatePairId);
- }
- });
- // Fallback for Firefox and Chrome legacy stats.
- if (!activeCandidatePair) {
- results.forEach(function(report) {
- if (report.type === 'candidate-pair' && report.selected ||
- report.type === 'googCandidatePair' &&
- report.googActiveConnection === 'true') {
- activeCandidatePair = report;
- }
- });
- }
- if (activeCandidatePair && activeCandidatePair.remoteCandidateId) {
- remoteCandidate = results.get(activeCandidatePair.remoteCandidateId);
- }
- if (remoteCandidate) {
- if (remoteCandidate.ip && remoteCandidate.port) {
- peerDiv.innerHTML = '<strong>Connected to:</strong> ' +
- remoteCandidate.ip + ':' + remoteCandidate.port;
- } else if (remoteCandidate.ipAddress && remoteCandidate.portNumber) {
- // Fall back to old names.
- peerDiv.innerHTML = '<strong>Connected to:</strong> ' +
- remoteCandidate.ipAddress +
- ':' + remoteCandidate.portNumber;
- }
- }
- }, function(err) {
- console.log(err);
- });
- localPeerConnection.getStats(null)
- .then(function(results) {
- var statsString = dumpStats(results);
- senderStatsDiv.innerHTML = '<h2>Sender stats</h2>' + statsString;
- }, function(err) {
- console.log(err);
- });
- } else {
- console.log('Not connected yet');
- }
- // Collect some stats from the video tags.
- if (localVideo.videoWidth) {
- localVideoStatsDiv.innerHTML = '<strong>Video dimensions:</strong> ' +
- localVideo.videoWidth + 'x' + localVideo.videoHeight + 'px';
- }
- if (remoteVideo.videoWidth) {
- remoteVideoStatsDiv.innerHTML = '<strong>Video dimensions:</strong> ' +
- remoteVideo.videoWidth + 'x' + remoteVideo.videoHeight + 'px';
- }
-}, 1000);
-
-// Dumping a stats variable as a string.
-// might be named toString?
-function dumpStats(results) {
- var statsString = '';
- results.forEach(function(res) {
- statsString += '<h3>Report type=';
- statsString += res.type;
- statsString += '</h3>\n';
- statsString += 'id ' + res.id + '<br>\n';
- statsString += 'time ' + res.timestamp + '<br>\n';
- Object.keys(res).forEach(function(k) {
- if (k !== 'timestamp' && k !== 'type' && k !== 'id') {
- statsString += k + ': ' + res[k] + '<br>\n';
- }
- });
- });
- return statsString;
-}
-
-// Utility to show the value of a range in a sibling span element
-function displayRangeValue(e) {
- var span = e.target.parentElement.querySelector('span');
- span.textContent = e.target.value;
- displayGetUserMediaConstraints();
-}