<!DOCTYPE html>
<html>
<head><title>GetUserMedia test</title></head>
<body>
  <script src="ssim.js"></script>
  <script src="blackframe.js"></script>
<script>

var resolutions = [[640, 480],
                   [1280, 720]];
var isVideoInputFound = false;
var results = {};
var isTestDone = false;
var durationMs = 20000;

function testNextResolution() {
  var nextResolution = resolutions.shift();
  if (nextResolution == undefined) {
    reportTestDone();
    return;
  }
  var test = new CameraTest(nextResolution);
  test.start();
  setTimeout(
    function() {
      test.stop();
      testNextResolution();
    },
    durationMs);
}

function reportTestDone() {
  console.log('tests completed');
  isTestDone = true;
}

function getResults() {
  return results;
}

function resolutionMatchesIndependentOfRotation(aWidth, aHeight,
                                                bWidth, bHeight) {
  return (aWidth === bWidth && aHeight === bHeight) ||
         (aWidth === bHeight && aHeight === bWidth);
}

function saveResult(resolution, verdict) {
  results[resolution] = verdict;
}

// Check if a video input exists
function checkVideoInput() {
  navigator.mediaDevices.enumerateDevices()
      .then(findVideoInput)
      .catch(gotEnumerateDevicesError);
}

function findVideoInput(devices) {
  isVideoInputFound = devices.some(dev => dev.kind == 'videoinput');
}

function gotEnumerateDevicesError(error) {
  console.log('navigator.mediaDevices.enumerateDevices error: ', error);
  results.cameraErrors.push('EnumerateDevices error: ' + error.toString());
}

function CameraTest(resolution) {
  this.resolution = resolution;
  this.localVideo = document.createElement('video');
  this.localVideo.id = 'local-video';
  this.localVideo.autoplay = true;
  document.body.appendChild(this.localVideo);
  this.localStream = null;
  this.canvas = document.createElement('canvas');
  this.context = this.canvas.getContext('2d');
  this.previousFrame = [];
  this.identicalFrameSsimThreshold = 0.985;
  this.frameComparator = new Ssim();
  this.results = {cameraErrors: [],
      frameStats: {numBlackFrames: 0, numFrozenFrames:0, numFrames: 0}};

  this.constraints = {
    "audio": false,
    "video": {
      "mandatory" : {
          "maxWidth": this.resolution[0].toString(),
          "maxHeight": this.resolution[1].toString(),
          "minWidth": this.resolution[0].toString(),
          "minHeight": this.resolution[1].toString()
      },
    }
  };
}

CameraTest.prototype = {

  start: function() {
    this.localVideo.addEventListener('play',
        this.startCheckingVideoFrames.bind(this), false);

    navigator.mediaDevices.getUserMedia(this.constraints)
        .then(this.gotLocalStream.bind(this))
        .catch(this.gotUserMediaError.bind(this));
  },

  gotLocalStream: function(stream) {
    this.localStream = stream;
    this.localVideo.srcObject = stream;
  },

  gotUserMediaError: function(error) {
    console.log('navigator.mediaDevices.getUserMedia error: ', error);
    this.results.cameraErrors.push('GetUserMedia error: ' + error.toString());
  },

  startCheckingVideoFrames: function() {
    if (!resolutionMatchesIndependentOfRotation(this.localVideo.videoWidth,
        this.localVideo.videoHeight, this.resolution[0], this.resolution[1])) {
      this.results.cameraErrors.push('resolution', 'Got ' +
          this.localVideo.videoWidth + 'x' + this.localVideo.videoHeight +
          ', expected ' + this.resolution[0] + 'x' + this.resolution[1] +
          ' or rotated version thereof');
    }

    this.videoFrameChecker = setInterval(this.checkVideoFrame.bind(this), 20);
  },

  checkVideoFrame: function() {
    this.context.drawImage(this.localVideo, 0, 0, this.canvas.width,
      this.canvas.height);
    var imageData = this.context.getImageData(0, 0, this.canvas.width,
      this.canvas.height);

    if (isBlackFrame(imageData.data, imageData.data.length)) {
      this.results.frameStats.numBlackFrames++;
    }

    if (this.frameComparator.calculate(this.previousFrame, imageData.data) >
      this.identicalFrameSsimThreshold) {
      this.results.frameStats.numFrozenFrames++;
    }

    this.previousFrame = imageData.data;
    this.results.frameStats.numFrames++;
  },

  stop: function() {
    clearInterval(this.videoFrameChecker);
    saveResult(this.resolution, this.results);
    this.localStream.getTracks().forEach(function(track) {
      track.stop();
    });
    document.body.removeChild(this.localVideo);
  },
}

window.onload = testNextResolution;
window.onerror = function (message, filename, lineno, colno, error) {
  console.log("Something went wrong, here is the stack trace --> %s",
      error.stack);
};
</script>
</body>
</html>
