Index: tools/perf/page_sets/webrtc_cases/audio.js |
diff --git a/tools/perf/page_sets/webrtc_cases/audio.js b/tools/perf/page_sets/webrtc_cases/audio.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2485837ac9d2b2ee5e42173de19702f215687ef0 |
--- /dev/null |
+++ b/tools/perf/page_sets/webrtc_cases/audio.js |
@@ -0,0 +1,302 @@ |
+/* |
+ * 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 audio2 = document.querySelector('audio#audio2'); |
+var callButton = document.querySelector('button#callButton'); |
+var hangupButton = document.querySelector('button#hangupButton'); |
+var codecSelector = document.querySelector('select#codec'); |
+hangupButton.disabled = true; |
+callButton.onclick = call; |
+hangupButton.onclick = hangup; |
+ |
+var pc1; |
+var pc2; |
+var localStream; |
+ |
+var bitrateGraph; |
+var bitrateSeries; |
+ |
+var packetGraph; |
+var packetSeries; |
+ |
+var lastResult; |
+ |
+var offerOptions = { |
+ offerToReceiveAudio: 1, |
+ offerToReceiveVideo: 0, |
+ voiceActivityDetection: false |
+}; |
+ |
+function gotStream(stream) { |
+ hangupButton.disabled = false; |
+ trace('Received local stream'); |
+ localStream = stream; |
+ var audioTracks = localStream.getAudioTracks(); |
+ if (audioTracks.length > 0) { |
+ trace('Using Audio device: ' + audioTracks[0].label); |
+ } |
+ pc1.addStream(localStream); |
+ trace('Adding Local Stream to peer connection'); |
+ |
+ pc1.createOffer( |
+ offerOptions |
+ ).then( |
+ gotDescription1, |
+ onCreateSessionDescriptionError |
+ ); |
+ |
+ bitrateSeries = new TimelineDataSeries(); |
+ bitrateGraph = new TimelineGraphView('bitrateGraph', 'bitrateCanvas'); |
+ bitrateGraph.updateEndDate(); |
+ |
+ packetSeries = new TimelineDataSeries(); |
+ packetGraph = new TimelineGraphView('packetGraph', 'packetCanvas'); |
+ packetGraph.updateEndDate(); |
+} |
+ |
+function onCreateSessionDescriptionError(error) { |
+ trace('Failed to create session description: ' + error.toString()); |
+} |
+ |
+function call() { |
+ callButton.disabled = true; |
+ codecSelector.disabled = true; |
+ trace('Starting call'); |
+ var servers = null; |
+ var pcConstraints = { |
+ 'optional': [] |
+ }; |
+ pc1 = new RTCPeerConnection(servers, pcConstraints); |
+ trace('Created local peer connection object pc1'); |
+ pc1.onicecandidate = function(e) { |
+ onIceCandidate(pc1, e); |
+ }; |
+ pc2 = new RTCPeerConnection(servers, pcConstraints); |
+ trace('Created remote peer connection object pc2'); |
+ pc2.onicecandidate = function(e) { |
+ onIceCandidate(pc2, e); |
+ }; |
+ pc2.onaddstream = gotRemoteStream; |
+ trace('Requesting local stream'); |
+ navigator.mediaDevices.getUserMedia({ |
+ audio: true, |
+ video: false |
+ }) |
+ .then(gotStream) |
+ .catch(function(e) { |
+ alert('getUserMedia() error: ' + e.name); |
+ }); |
+} |
+ |
+function gotDescription1(desc) { |
+ trace('Offer from pc1 \n' + desc.sdp); |
+ pc1.setLocalDescription(desc).then( |
+ function() { |
+ desc.sdp = forceChosenAudioCodec(desc.sdp); |
+ pc2.setRemoteDescription(desc).then( |
+ function() { |
+ pc2.createAnswer().then( |
+ gotDescription2, |
+ onCreateSessionDescriptionError |
+ ); |
+ }, |
+ onSetSessionDescriptionError |
+ ); |
+ }, |
+ onSetSessionDescriptionError |
+ ); |
+} |
+ |
+function gotDescription2(desc) { |
+ trace('Answer from pc2 \n' + desc.sdp); |
+ pc2.setLocalDescription(desc).then( |
+ function() { |
+ desc.sdp = forceChosenAudioCodec(desc.sdp); |
+ pc1.setRemoteDescription(desc).then( |
+ function() { |
+ }, |
+ onSetSessionDescriptionError |
+ ); |
+ }, |
+ onSetSessionDescriptionError |
+ ); |
+} |
+ |
+function hangup() { |
+ trace('Ending call'); |
+ localStream.getTracks().forEach(function(track) { |
+ track.stop(); |
+ }); |
+ pc1.close(); |
+ pc2.close(); |
+ pc1 = null; |
+ pc2 = null; |
+ hangupButton.disabled = true; |
+ callButton.disabled = false; |
+ codecSelector.disabled = false; |
+} |
+ |
+function gotRemoteStream(e) { |
+ audio2.srcObject = e.stream; |
+ trace('Received remote stream'); |
+} |
+ |
+function getOtherPc(pc) { |
+ return (pc === pc1) ? pc2 : pc1; |
+} |
+ |
+function getName(pc) { |
+ return (pc === pc1) ? 'pc1' : 'pc2'; |
+} |
+ |
+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() { |
+ trace('AddIceCandidate success.'); |
+} |
+ |
+function onAddIceCandidateError(error) { |
+ trace('Failed to add ICE Candidate: ' + error.toString()); |
+} |
+ |
+function onSetSessionDescriptionError(error) { |
+ trace('Failed to set session description: ' + error.toString()); |
+} |
+ |
+function forceChosenAudioCodec(sdp) { |
+ return maybePreferCodec(sdp, 'audio', 'send', codecSelector.value); |
+} |
+ |
+// Copied from AppRTC's sdputils.js: |
+ |
+// Sets |codec| as the default |type| codec if it's present. |
+// The format of |codec| is 'NAME/RATE', e.g. 'opus/48000'. |
+function maybePreferCodec(sdp, type, dir, codec) { |
+ var str = type + ' ' + dir + ' codec'; |
+ if (codec === '') { |
+ trace('No preference on ' + str + '.'); |
+ return sdp; |
+ } |
+ |
+ trace('Prefer ' + str + ': ' + codec); |
+ |
+ var sdpLines = sdp.split('\r\n'); |
+ |
+ // Search for m line. |
+ var mLineIndex = findLine(sdpLines, 'm=', type); |
+ if (mLineIndex === null) { |
+ return sdp; |
+ } |
+ |
+ // If the codec is available, set it as the default in m line. |
+ var codecIndex = findLine(sdpLines, 'a=rtpmap', codec); |
+ console.log('codecIndex', codecIndex); |
+ if (codecIndex) { |
+ var payload = getCodecPayloadType(sdpLines[codecIndex]); |
+ if (payload) { |
+ sdpLines[mLineIndex] = setDefaultCodec(sdpLines[mLineIndex], payload); |
+ } |
+ } |
+ |
+ sdp = sdpLines.join('\r\n'); |
+ return sdp; |
+} |
+ |
+// Find the line in sdpLines that starts with |prefix|, and, if specified, |
+// contains |substr| (case-insensitive search). |
+function findLine(sdpLines, prefix, substr) { |
+ return findLineInRange(sdpLines, 0, -1, prefix, substr); |
+} |
+ |
+// Find the line in sdpLines[startLine...endLine - 1] that starts with |prefix| |
+// and, if specified, contains |substr| (case-insensitive search). |
+function findLineInRange(sdpLines, startLine, endLine, prefix, substr) { |
+ var realEndLine = endLine !== -1 ? endLine : sdpLines.length; |
+ for (var i = startLine; i < realEndLine; ++i) { |
+ if (sdpLines[i].indexOf(prefix) === 0) { |
+ if (!substr || |
+ sdpLines[i].toLowerCase().indexOf(substr.toLowerCase()) !== -1) { |
+ return i; |
+ } |
+ } |
+ } |
+ return null; |
+} |
+ |
+// Gets the codec payload type from an a=rtpmap:X line. |
+function getCodecPayloadType(sdpLine) { |
+ var pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+'); |
+ var result = sdpLine.match(pattern); |
+ return (result && result.length === 2) ? result[1] : null; |
+} |
+ |
+// Returns a new m= line with the specified codec as the first one. |
+function setDefaultCodec(mLine, payload) { |
+ var elements = mLine.split(' '); |
+ |
+ // Just copy the first three parameters; codec order starts on fourth. |
+ var newLine = elements.slice(0, 3); |
+ |
+ // Put target payload first and copy in the rest. |
+ newLine.push(payload); |
+ for (var i = 3; i < elements.length; i++) { |
+ if (elements[i] !== payload) { |
+ newLine.push(elements[i]); |
+ } |
+ } |
+ return newLine.join(' '); |
+} |
+ |
+// query getStats every second |
+window.setInterval(function() { |
+ if (!window.pc1) { |
+ return; |
+ } |
+ window.pc1.getStats(null).then(function(res) { |
+ res.forEach(function(report) { |
+ var bytes; |
+ var packets; |
+ var now = report.timestamp; |
+ if ((report.type === 'outboundrtp') || |
+ (report.type === 'outbound-rtp') || |
+ (report.type === 'ssrc' && report.bytesSent)) { |
+ bytes = report.bytesSent; |
+ packets = report.packetsSent; |
+ if (lastResult && lastResult.get(report.id)) { |
+ // calculate bitrate |
+ var bitrate = 8 * (bytes - lastResult.get(report.id).bytesSent) / |
+ (now - lastResult.get(report.id).timestamp); |
+ |
+ // append to chart |
+ bitrateSeries.addPoint(now, bitrate); |
+ bitrateGraph.setDataSeries([bitrateSeries]); |
+ bitrateGraph.updateEndDate(); |
+ |
+ // calculate number of packets and append to chart |
+ packetSeries.addPoint(now, packets - |
+ lastResult.get(report.id).packetsSent); |
+ packetGraph.setDataSeries([packetSeries]); |
+ packetGraph.updateEndDate(); |
+ } |
+ } |
+ }); |
+ lastResult = res; |
+ }); |
+}, 1000); |