1/*
2 * Copyright 2017 The Chromium Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6/*jshint esversion: 6 */
7
8'use strict';
9
10const $ = document.getElementById.bind(document);
11
12function logError(err) {
13  console.error(err);
14}
15
16// Available resolutions to switch between. These are 4:3 resolutions chosen
17// since they have significant distance between them and are quite common. E.g.
18// they can be selected for youtube videos. We also avoid higher resolutions
19// since they consume a lot of resources.
20const RESOLUTIONS = [
21  {w:320, h:240},
22  {w:480, h:360},
23  {w:640, h:480},
24  {w:1280, h:720},
25];
26
27class TestRunner {
28  constructor(runtimeSeconds, switchResolutionDelayMillis) {
29    this.runtimeSeconds = runtimeSeconds;
30    this.switchResolutionDelayMillis = switchResolutionDelayMillis;
31    this.videoElements = [];
32    this.peerConnections = [];
33    this.numConnections = 0;
34    this.iteration = 0;
35    this.startTime = 0;  // initialized to dummy value
36    this.status = this.getStatusInternal_();
37  }
38
39  addPeerConnection() {
40    const videoElement = document.createElement('video');
41    videoElement.autoplay = true;
42    $('body').appendChild(videoElement);
43    this.videoElements.push(videoElement);
44    this.peerConnections.push(
45        new PeerConnection(videoElement, RESOLUTIONS, cpuOveruseDetection));
46  }
47
48  runTest() {
49    const promises = this.peerConnections.map((conn) => conn.start());
50    Promise.all(promises)
51        .then(() => {
52          this.startTime = Date.now();
53          this.switchResolutionLoop();
54        })
55        .catch((e) => {throw e});
56  }
57
58  switchResolutionLoop() {
59    this.iteration++;
60    this.status = this.getStatusInternal_();
61    $('status').textContent = this.status;
62    if (this.status != 'ok-done') {
63      Promise.all(this.peerConnections.map((pc) => pc.switchToRandomStream()))
64          .then(
65              () => setTimeout(
66                  () => this.switchResolutionLoop(),
67                  this.switchResolutionDelayMillis));
68    }
69  }
70
71  getStatus() {
72    return this.status;
73  }
74
75  getStatusInternal_() {
76    if (this.iteration == 0) {
77      return 'not-started';
78    }
79    try {
80      this.peerConnections.forEach((conn) => conn.verifyState());
81    } catch (e) {
82      return `failure: ${e.message}`;
83    }
84    const timeSpent = Date.now() - this.startTime;
85    if (timeSpent >= this.runtimeSeconds * 1000) {
86      return 'ok-done';
87    }
88    return `running, iteration: ${this.iteration}`;
89  }
90}
91
92// Declare testRunner so that the Python code can access it to query status.
93// Also allows us to access it easily in dev tools for debugging.
94let testRunner;
95// Set from the Python test runner
96let cpuOveruseDetection = null;
97
98function startTest(
99    runtimeSeconds, numPeerConnections, switchResolutionDelayMillis) {
100  testRunner = new TestRunner(runtimeSeconds, switchResolutionDelayMillis);
101  for (let i = 0; i < numPeerConnections; i++) {
102    testRunner.addPeerConnection();
103  }
104  testRunner.runTest();
105}
106
107function getStatus() {
108  return testRunner ? testRunner.getStatus() : 'not-initialized';
109}
110
111