1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5// These must match with how the video and canvas tags are declared in html. 6const VIDEO_TAG_WIDTH = 320; 7const VIDEO_TAG_HEIGHT = 240; 8 9// Fake video capture background green is of value 135. 10const COLOR_BACKGROUND_GREEN = 135; 11 12// Number of test events to occur before the test pass. When the test pass, 13// the function gAllEventsOccured is called. 14var gNumberOfExpectedEvents = 0; 15 16// Number of events that currently have occurred. 17var gNumberOfEvents = 0; 18 19var gAllEventsOccured = function () {}; 20 21// Use this function to set a function that will be called once all expected 22// events has occurred. 23function setAllEventsOccuredHandler(handler) { 24 gAllEventsOccured = handler; 25} 26 27// Tells the C++ code we succeeded, which will generally exit the test. 28function reportTestSuccess() { 29 window.domAutomationController.send('OK'); 30} 31 32// Returns a custom return value to the test. 33function sendValueToTest(value) { 34 window.domAutomationController.send(value); 35} 36 37// Immediately fails the test on the C++ side. 38function failTest(reason) { 39 var error = new Error(reason); 40 window.domAutomationController.send(error.stack); 41} 42 43function detectVideoPlaying(videoElementName, callback) { 44 detectVideo(videoElementName, isVideoPlaying, callback); 45} 46 47function detectVideoStopped(videoElementName, callback) { 48 detectVideo(videoElementName, 49 function (pixels, previous_pixels) { 50 return !isVideoPlaying(pixels, previous_pixels); 51 }, 52 callback); 53} 54 55function detectBlackVideo(videoElementName, callback) { 56 detectVideo(videoElementName, 57 function (pixels, previous_pixels) { 58 return isVideoBlack(pixels); 59 }, 60 callback); 61} 62 63function detectVideo(videoElementName, predicate, callback) { 64 console.log('Looking at video in element ' + videoElementName); 65 66 var width = VIDEO_TAG_WIDTH; 67 var height = VIDEO_TAG_HEIGHT; 68 var videoElement = $(videoElementName); 69 var canvas = $(videoElementName + '-canvas'); 70 var oldPixels = []; 71 var waitVideo = setInterval(function() { 72 var context = canvas.getContext('2d'); 73 context.drawImage(videoElement, 0, 0, width, height); 74 var pixels = context.getImageData(0, 0 , width, height / 3).data; 75 // Check that there is an old and a new picture with the same size to 76 // compare and use the function |predicate| to detect the video state in 77 // that case. 78 if (oldPixels.length == pixels.length && 79 predicate(pixels, oldPixels)) { 80 console.log('Done looking at video in element ' + videoElementName); 81 clearInterval(waitVideo); 82 callback(videoElement.videoWidth, videoElement.videoHeight); 83 } 84 oldPixels = pixels; 85 }, 200); 86} 87 88function waitForVideoWithResolution(element, expected_width, expected_height) { 89 addExpectedEvent(); 90 detectVideoPlaying(element, 91 function (width, height) { 92 assertEquals(expected_width, width); 93 assertEquals(expected_height, height); 94 eventOccured(); 95 }); 96} 97 98function waitForVideo(videoElement) { 99 addExpectedEvent(); 100 detectVideoPlaying(videoElement, function () { eventOccured(); }); 101} 102 103function waitForVideoToStop(videoElement) { 104 addExpectedEvent(); 105 detectVideoStopped(videoElement, function () { eventOccured(); }); 106} 107 108function waitForBlackVideo(videoElement) { 109 addExpectedEvent(); 110 detectBlackVideo(videoElement, function () { eventOccured(); }); 111} 112 113// Calculates the current frame rate and compares to |expected_frame_rate| 114// |callback| is triggered with value |true| if the calculated frame rate 115// is +-1 the expected or |false| if five calculations fail to match 116// |expected_frame_rate|. 117function validateFrameRate(videoElementName, expected_frame_rate, callback) { 118 var videoElement = $(videoElementName); 119 var startTime = new Date().getTime(); 120 var decodedFrames = videoElement.webkitDecodedFrameCount; 121 var attempts = 0; 122 123 if (videoElement.readyState <= HTMLMediaElement.HAVE_CURRENT_DATA || 124 videoElement.paused || videoElement.ended) { 125 failTest("getFrameRate - " + videoElementName + " is not plaing."); 126 return; 127 } 128 129 var waitVideo = setInterval(function() { 130 attempts++; 131 currentTime = new Date().getTime(); 132 deltaTime = (currentTime - startTime) / 1000; 133 startTime = currentTime; 134 135 // Calculate decoded frames per sec. 136 var fps = 137 (videoElement.webkitDecodedFrameCount - decodedFrames) / deltaTime; 138 decodedFrames = videoElement.webkitDecodedFrameCount; 139 140 console.log('FrameRate in ' + videoElementName + ' is ' + fps); 141 if (fps < expected_frame_rate + 1 && fps > expected_frame_rate - 1) { 142 clearInterval(waitVideo); 143 callback(true); 144 } else if (attempts == 5) { 145 clearInterval(waitVideo); 146 callback(false); 147 } 148 }, 1000); 149} 150 151function waitForConnectionToStabilize(peerConnection, callback) { 152 peerConnection.onsignalingstatechange = function(event) { 153 if (peerConnection.signalingState == 'stable') { 154 peerConnection.onsignalingstatechange = null; 155 callback(); 156 } 157 } 158} 159 160// Adds an expected event. You may call this function many times to add more 161// expected events. Each expected event must later be matched by a call to 162// eventOccurred. When enough events have occurred, the "all events occurred 163// handler" will be called. 164function addExpectedEvent() { 165 ++gNumberOfExpectedEvents; 166} 167 168// See addExpectedEvent. 169function eventOccured() { 170 ++gNumberOfEvents; 171 if (gNumberOfEvents == gNumberOfExpectedEvents) { 172 gAllEventsOccured(); 173 } 174} 175 176// This very basic video verification algorithm will be satisfied if any 177// pixels are changed. 178function isVideoPlaying(pixels, previousPixels) { 179 for (var i = 0; i < pixels.length; i++) { 180 if (pixels[i] != previousPixels[i]) { 181 return true; 182 } 183 } 184 return false; 185} 186 187function isVideoBlack(pixels) { 188 for (var i = 0; i < pixels.length; i++) { 189 // |pixels| is in RGBA. Ignore the alpha channel. 190 // We allow it to be off by 1, to account for rounding errors in YUV 191 // conversion. 192 if (pixels[i] != 0 && pixels[i] != 1 && (i + 1) % 4 != 0) { 193 return false; 194 } 195 } 196 return true; 197} 198 199// This function matches |left| and |right| and fails the test if the 200// values don't match using normal javascript equality (i.e. the hard 201// types of the operands aren't checked). 202function assertEquals(expected, actual) { 203 if (actual != expected) { 204 failTest("expected '" + expected + "', got '" + actual + "'."); 205 } 206} 207 208function assertNotEquals(expected, actual) { 209 if (actual === expected) { 210 failTest("expected '" + expected + "', got '" + actual + "'."); 211 } 212} 213 214