| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // The tests here cover the end-to-end functionality of tab capturing and | 5 // The tests here cover the end-to-end functionality of tab capturing and |
| 6 // playback as video. The page generates a test patter (moving balls) and | 6 // playback as video. The page generates a test patter (moving balls) and |
| 7 // the rendering output of the tab is captured into a LocalMediaStream. Then, | 7 // the rendering output of the tab is captured into a LocalMediaStream. Then, |
| 8 // the LocalMediaStream is plugged into a video element for playback. | 8 // the LocalMediaStream is plugged into a video element for playback. |
| 9 // | 9 // |
| 10 | 10 |
| 11 // Global to prevent gc from eating the video tag. | 11 // Global to prevent gc from eating the video tag. |
| 12 var video = null; | 12 var video = null; |
| 13 var capture_stream = null; | 13 var captureStream = null; |
| 14 | 14 |
| 15 function TestStream(stream) { | 15 function stopStream(stream) { |
| 16 // Create video and canvas elements, but no need to append them to the | 16 const tracks = stream.getTracks(); |
| 17 // DOM. | 17 for (let i = 0; i < tracks.length; ++i) { |
| 18 tracks[i].stop(); |
| 19 } |
| 20 chrome.test.assertFalse(stream.active); |
| 21 } |
| 22 |
| 23 function connectToVideoAndRunTest(stream) { |
| 24 if (!stream) { |
| 25 chrome.test.fail(chrome.runtime.lastError.message || 'null stream'); |
| 26 return; |
| 27 } |
| 28 |
| 29 // Create the video element, to play out the captured video; but there's no |
| 30 // need to append it to the DOM. |
| 18 video = document.createElement("video"); | 31 video = document.createElement("video"); |
| 19 video.width = 1920; | 32 video.width = 1920; |
| 20 video.height = 1080; | 33 video.height = 1080; |
| 21 video.addEventListener("error", chrome.test.fail); | 34 video.addEventListener("error", chrome.test.fail); |
| 22 | 35 |
| 36 // Create a canvas and add it to the test page being captured. The draw() |
| 37 // function below will update the canvas's content, triggering tab capture for |
| 38 // each animation frame. |
| 23 var canvas = document.createElement("canvas"); | 39 var canvas = document.createElement("canvas"); |
| 24 canvas.width = video.width; | 40 canvas.width = video.width; |
| 25 canvas.height = video.height; | 41 canvas.height = video.height; |
| 26 var context = canvas.getContext("2d"); | 42 var context = canvas.getContext("2d"); |
| 27 document.body.appendChild(canvas); | 43 document.body.appendChild(canvas); |
| 28 var start_time = new Date().getTime(); | 44 var start_time = new Date().getTime(); |
| 29 | 45 |
| 30 // Play the LocalMediaStream in the video element. | 46 // Play the LocalMediaStream in the video element. |
| 31 video.src = URL.createObjectURL(stream); | 47 video.src = URL.createObjectURL(stream); |
| 32 video.play(); | 48 video.play(); |
| 33 | 49 |
| 34 var frame = 0; | 50 var frame = 0; |
| 35 function draw() { | 51 function draw() { |
| 36 // Run for 10 seconds. | 52 // Run for 15 seconds. |
| 37 if (new Date().getTime() - start_time > 10000) { | 53 if (new Date().getTime() - start_time > 15000) { |
| 38 chrome.test.succeed(); | 54 chrome.test.succeed(); |
| 39 // Note that the API testing framework might not terminate if we keep | 55 // Note that the API testing framework might not terminate if we keep |
| 40 // animating and capturing, so we have to make sure that we stop doing | 56 // animating and capturing, so we have to make sure that we stop doing |
| 41 // that here. | 57 // that here. |
| 42 if (capture_stream) { | 58 if (captureStream) { |
| 43 capture_stream.stop(); | 59 stopStream(captureStream); |
| 60 captureStream = null; |
| 44 } | 61 } |
| 45 stream.stop(); | 62 stopStream(stream); |
| 46 return; | 63 return; |
| 47 } | 64 } |
| 48 requestAnimationFrame(draw); | 65 requestAnimationFrame(draw); |
| 49 frame = frame + 1; | 66 frame = frame + 1; |
| 50 context.fillStyle = 'rgb(255,255,255)'; | 67 context.fillStyle = 'rgb(255,255,255)'; |
| 51 context.fillRect( 0, 0, canvas.width, canvas.height ); | 68 context.fillRect(0, 0, canvas.width, canvas.height ); |
| 52 for (var j = 0; j < 200; j++) { | 69 for (var j = 0; j < 200; j++) { |
| 53 var i = (j + frame) % 200; | 70 var i = (j + frame) % 200; |
| 54 var t = (frame + 3000) * (0.01 + i / 8000.0); | 71 var t = (frame + 3000) * (0.01 + i / 8000.0); |
| 55 var x = (Math.sin( t ) * 0.45 + 0.5) * canvas.width; | 72 var x = (Math.sin( t ) * 0.45 + 0.5) * canvas.width; |
| 56 var y = (Math.cos( t * 0.9 ) * 0.45 + 0.5) * canvas.height; | 73 var y = (Math.cos( t * 0.9 ) * 0.45 + 0.5) * canvas.height; |
| 57 context.fillStyle = 'rgb(' + (255 - i) + ',' + (155 +i) + ', ' + i + ')'; | 74 context.fillStyle = 'rgb(' + (255 - i) + ',' + (155 +i) + ', ' + i + ')'; |
| 58 context.beginPath(); | 75 context.beginPath(); |
| 59 context.arc(x, y, 50, 0, Math.PI * 2, true); | 76 context.arc(x, y, 50, 0, Math.PI * 2, true); |
| 60 context.closePath(); | 77 context.closePath(); |
| 61 context.fill(); | 78 context.fill(); |
| 62 } | 79 } |
| 63 } | 80 } |
| 64 | 81 |
| 65 // Kick it off. | 82 // Kick it off. |
| 66 draw(); | 83 draw(); |
| 67 } | 84 } |
| 68 | 85 |
| 69 // Set up a WebRTC connection and pipe |stream| through it. | 86 // Set up a WebRTC connection and pipe |stream| through it. |
| 70 function testThroughWebRTC(stream) { | 87 function testThroughWebRTC(stream) { |
| 71 capture_stream = stream; | 88 captureStream = stream; |
| 72 console.log("Testing through webrtc."); | 89 console.log("Testing through webrtc."); |
| 73 var sender = new RTCPeerConnection(); | 90 var sender = new RTCPeerConnection(); |
| 74 var receiver = new RTCPeerConnection(); | 91 var receiver = new RTCPeerConnection(); |
| 75 sender.onicecandidate = function (event) { | 92 sender.onicecandidate = function (event) { |
| 76 if (event.candidate) { | 93 if (event.candidate) { |
| 77 receiver.addIceCandidate(new RTCIceCandidate(event.candidate)); | 94 receiver.addIceCandidate(new RTCIceCandidate(event.candidate)); |
| 78 } | 95 } |
| 79 }; | 96 }; |
| 80 receiver.onicecandidate = function (event) { | 97 receiver.onicecandidate = function (event) { |
| 81 if (event.candidate) { | 98 if (event.candidate) { |
| 82 sender.addIceCandidate(new RTCIceCandidate(event.candidate)); | 99 sender.addIceCandidate(new RTCIceCandidate(event.candidate)); |
| 83 } | 100 } |
| 84 }; | 101 }; |
| 85 receiver.onaddstream = function (event) { | 102 receiver.onaddstream = function (event) { |
| 86 TestStream(event.stream); | 103 connectToVideoAndRunTest(event.stream); |
| 87 }; | 104 }; |
| 88 sender.addStream(stream); | 105 sender.addStream(stream); |
| 89 sender.createOffer(function (sender_description) { | 106 sender.createOffer(function (sender_description) { |
| 90 sender.setLocalDescription(sender_description); | 107 sender.setLocalDescription(sender_description); |
| 91 receiver.setRemoteDescription(sender_description); | 108 receiver.setRemoteDescription(sender_description); |
| 92 receiver.createAnswer(function (receiver_description) { | 109 receiver.createAnswer(function (receiver_description) { |
| 93 receiver.setLocalDescription(receiver_description); | 110 receiver.setLocalDescription(receiver_description); |
| 94 sender.setRemoteDescription(receiver_description); | 111 sender.setRemoteDescription(receiver_description); |
| 95 }, function() { | 112 }, function() { |
| 96 }); | 113 }); |
| 97 }, function() { | 114 }, function() { |
| 98 }); | 115 }); |
| 99 } | 116 } |
| 100 | 117 |
| 101 function tabCapturePerformanceTest() { | 118 function tabCapturePerformanceTest() { |
| 102 var f = TestStream; | 119 var f = connectToVideoAndRunTest; |
| 103 if (parseInt(window.location.href.split('?WebRTC=')[1])) { | 120 if (parseInt(window.location.href.split('?WebRTC=')[1])) { |
| 104 f = testThroughWebRTC; | 121 f = testThroughWebRTC; |
| 105 } | 122 } |
| 106 var fps = parseInt(window.location.href.split('&fps=')[1]); | 123 var fps = parseInt(window.location.href.split('&fps=')[1]); |
| 107 chrome.tabCapture.capture( | 124 chrome.tabCapture.capture( |
| 108 { video: true, audio: false, | 125 { video: true, audio: false, |
| 109 videoConstraints: { | 126 videoConstraints: { |
| 110 mandatory: { | 127 mandatory: { |
| 111 minWidth: 1920, | 128 minWidth: 1920, |
| 112 minHeight: 1080, | 129 minHeight: 1080, |
| 113 maxWidth: 1920, | 130 maxWidth: 1920, |
| 114 maxHeight: 1080, | 131 maxHeight: 1080, |
| 115 maxFrameRate: fps, | 132 maxFrameRate: fps, |
| 116 } | 133 } |
| 117 } | 134 } |
| 118 }, | 135 }, |
| 119 f); | 136 f); |
| 120 } | 137 } |
| 121 | 138 |
| 122 chrome.test.runTests([ tabCapturePerformanceTest ]); | 139 chrome.test.runTests([ tabCapturePerformanceTest ]); |
| 123 | 140 |
| 124 // TODO(hubbe): Consider capturing audio as well, need to figure out how to | 141 // TODO(hubbe): Consider capturing audio as well, need to figure out how to |
| 125 // capture relevant statistics for that though. | 142 // capture relevant statistics for that though. |
| OLD | NEW |