Index: tools/perf/page_sets/webrtc_cases/constraints.js |
diff --git a/tools/perf/page_sets/webrtc_cases/constraints.js b/tools/perf/page_sets/webrtc_cases/constraints.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..16cf173d8e294feff7b33f8f5a731e83db49b095 |
--- /dev/null |
+++ b/tools/perf/page_sets/webrtc_cases/constraints.js |
@@ -0,0 +1,307 @@ |
+/* |
+ * 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); |
+ localPeerConnection.addStream(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'); |
+ if (e.candidate) { |
+ remotePeerConnection.addIceCandidate(e.candidate) |
+ .then( |
+ onAddIceCandidateSuccess, |
+ onAddIceCandidateError |
+ ); |
+ } |
+ }; |
+ remotePeerConnection.onicecandidate = function(e) { |
+ console.log('Candidate remotePeerConnection'); |
+ if (e.candidate) { |
+ localPeerConnection.addIceCandidate(e.candidate) |
+ .then( |
+ onAddIceCandidateSuccess, |
+ onAddIceCandidateError |
+ ); |
+ } |
+ }; |
+ remotePeerConnection.onaddstream = function(e) { |
+ console.log('remotePeerConnection got stream'); |
+ remoteVideo.srcObject = e.stream; |
+ }; |
+ 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 |
+ results.forEach(function(report) { |
+ if (report.type === 'candidatepair' && report.selected || |
+ report.type === 'googCandidatePair' && |
+ report.googActiveConnection === 'true') { |
+ activeCandidatePair = report; |
+ } |
+ }); |
+ if (activeCandidatePair && activeCandidatePair.remoteCandidateId) { |
+ remoteCandidate = results[activeCandidatePair.remoteCandidateId]; |
+ } |
+ if (remoteCandidate && remoteCandidate.ipAddress && |
+ remoteCandidate.portNumber) { |
+ 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(); |
+} |