/* * 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. */ /*jshint esversion: 6 */ 'use strict'; const $ = document.getElementById.bind(document); const MAIN_FEED_RESOLUTION = {w:1280, h:720}; // This resolution is what we typically get on Hangouts Meet. const SMALL_FEED_RESOLUTION = {w:182, h:136}; // This test frequently reports weird resolutions although the visuals look OK. // Hence, require lots of consecutive bad resolutions before failure. // TODO(kerl): Effectively disabled now, investigate why we get so many bad // resolution reports. const NUM_BAD_RESOLUTIONS_FOR_FAILURE = Number.MAX_SAFE_INTEGER; class TestRunner { constructor(numConnections, runtimeSeconds, iterationDelayMillis) { this.runtimeSeconds = runtimeSeconds; this.iterationDelayMillis = iterationDelayMillis; this.videoElements = []; this.mainFeed = null; this.peerConnections = []; this.numConnections = numConnections; this.iteration = 0; this.startTime = 0; // initialized to dummy value this.status = this.getStatusInternal_(); } runTest() { for (let i = 0; i < this.numConnections; i++) { const videoElement = document.createElement('video'); videoElement.autoplay = true; $('body').appendChild(videoElement); if (!this.mainFeed) { // The first created is the main feed. setSize(videoElement, MAIN_FEED_RESOLUTION); this.mainFeed = videoElement; } else { setSize(videoElement, SMALL_FEED_RESOLUTION); this.videoElements.push(videoElement); } this.peerConnections.push(new PeerConnection( videoElement, [MAIN_FEED_RESOLUTION], cpuOveruseDetection)); } const promises = this.peerConnections.map((conn) => conn.start()); Promise.all(promises) .then(() => { this.startTime = Date.now(); this.switchFeedLoop(); }) .catch((e) => {throw e}); } switchFeedLoop() { this.iteration++; this.status = this.getStatusInternal_(); $('status').textContent = this.status; if (this.status != 'ok-done') { const switchWith = Math.floor(Math.random() * this.videoElements.length); const newMainSrc = this.videoElements[switchWith].srcObject; this.videoElements[switchWith].srcObject = this.mainFeed.srcObject; this.mainFeed.srcObject = newMainSrc; setTimeout( () => this.switchFeedLoop(), this.iterationDelayMillis); } } getStatus() { return this.status; } getStatusInternal_() { if (this.iteration == 0) { return 'not-started'; } try { this.peerConnections.forEach( (conn) => conn.verifyState(NUM_BAD_RESOLUTIONS_FOR_FAILURE)); } catch (e) { return `failure: ${e.message}`; } const timeSpent = Date.now() - this.startTime; if (timeSpent >= this.runtimeSeconds * 1000) { return 'ok-done'; } else { return `running, iteration: ${this.iteration}`; } } } function setSize(element, size) { element.setAttribute('style', `width:${size.w}px;height:${size.h}px`); } // Declare testRunner so that the Python code can access it to query status. // Also allows us to access it easily in dev tools for debugging. let testRunner; // Set from the Python test runner let cpuOveruseDetection = null; function startTest( runtimeSeconds, numPeerConnections, iterationDelayMillis) { testRunner = new TestRunner( numPeerConnections, runtimeSeconds, iterationDelayMillis); testRunner.runTest(); } function getStatus() { return testRunner ? testRunner.getStatus() : 'not-initialized'; }