<html>
<head>
  <script type="text/javascript" src="webrtc_test_utilities.js"></script>
  <script type="text/javascript">
  $ = function(id) {
    return document.getElementById(id);
  };

  var gLocalStream = null;

  setAllEventsOccuredHandler(function() {
    gLocalStream.stop();
    reportTestSuccess();
  });

  function getSources() {
    MediaStreamTrack.getSources(function(devices) {
      document.title = 'Media devices available';
      sendValueToTest(JSON.stringify(devices));
    });
  }

  // Creates a MediaStream and renders it locally. When the video is detected to
  // be rolling, the stream should be stopped.
  function getUserMediaAndStop(constraints) {
    console.log('Calling getUserMediaAndStop.');
    navigator.webkitGetUserMedia(
        constraints,
        function(stream) { displayAndDetectVideo(stream, stopVideoTrack); },
        failedCallback);
  }

  // Requests getusermedia and expects it to fail. The error name is returned
  // to the test.
  function getUserMediaAndExpectFailure(constraints) {
    console.log('Calling getUserMediaAndExpectFailure.');
    navigator.webkitGetUserMedia(
        constraints,
        function(stream) { failTest('Unexpectedly succeeded getUserMedia.'); },
        function(error) { sendValueToTest(error.name); });
  }

  function renderClonedMediastreamAndStop(constraints, waitTimeInSeconds) {
    console.log('Calling renderClonedMediastreamAndStop.');
    navigator.webkitGetUserMedia(
        constraints,
        function(stream) {
          var s = stream.clone();
          assertEquals(stream.getVideoTracks().length, 1);
          assertEquals(s.getVideoTracks().length, 1);
          assertNotEquals(stream.getVideoTracks()[0].id,
                          s.getVideoTracks()[0].id);
          displayAndDetectVideo(
            s,
            function() {
              reportTestSuccess();
            });
        },
        failedCallback);
  }

  function renderDuplicatedMediastreamAndStop(constraints, waitTimeInSeconds) {
    console.log('Calling renderDuplicateMediastreamAndStop.');
    navigator.webkitGetUserMedia(
        constraints,
        function(stream) {
          s = new webkitMediaStream(stream);
          assertEquals(stream.getVideoTracks().length, 1);
          assertEquals(s.getVideoTracks().length, 1);
          assertEquals(stream.getVideoTracks()[0].id,
                       s.getVideoTracks()[0].id);
          displayAndDetectVideo(
            s,
            function() {
              reportTestSuccess();
            });
        },
        failedCallback);
  }

  function renderSameTrackMediastreamAndStop(constraints, waitTimeInSeconds) {
    console.log('Calling renderSameTrackMediastreamAndStop.');
    navigator.webkitGetUserMedia(
        constraints,
        function(stream) {
          s = new webkitMediaStream();
          s.addTrack(stream.getVideoTracks()[0]);
          assertEquals(s.getVideoTracks().length, 1);
          assertEquals(s.getVideoTracks().length, 1);
          assertEquals(stream.getVideoTracks()[0].id, s.getVideoTracks()[0].id);
          displayAndDetectVideo(
            s,
            function() {
              reportTestSuccess();
            });
        },
        failedCallback);
  }

  function renderClonedTrackMediastreamAndStop(constraints, waitTimeInSeconds) {
    console.log('Calling renderClonedTrackMediastreamAndStop.');
    navigator.webkitGetUserMedia(
        constraints,
        function(stream) {
          s = new webkitMediaStream();
          s.addTrack(stream.getVideoTracks()[0].clone());
          assertEquals(s.getVideoTracks().length, 1);
          assertEquals(s.getVideoTracks().length, 1);
          assertNotEquals(stream.getVideoTracks()[0].id,
                          s.getVideoTracks()[0].id)
          displayAndDetectVideo(
            s,
            function() {
              reportTestSuccess();
            });
        },
        failedCallback);
  }

  // Creates a MediaStream and renders it locally. When the video is detected to
  // be rolling we return ok-stream-running through the automation controller.
  function getUserMediaAndGetStreamUp(constraints, waitTimeInSeconds) {
    console.log('Calling getUserMediaAndGetStreamUp.');
    navigator.webkitGetUserMedia(
        constraints,
        function(stream) {
          displayAndDetectVideo(
            stream,
            function() {
              reportTestSuccess();
            });
        },
        failedCallback);
  }

  function getUserMediaAndRenderInSeveralVideoTags() {
    navigator.webkitGetUserMedia(
        {video: true},
        createMultipleVideoRenderersAndPause,
        function(error) { failedCallback(); });
  }

  // Gets a video stream up, analyses it and returns the aspect ratio to the
  // test through the automation controller.
  function getUserMediaAndAnalyseAndStop(constraints) {
    console.log('Calling getUserMediaAndAnalyseAndStop.');
    navigator.webkitGetUserMedia(
        constraints, displayDetectAndAnalyzeVideo, failedCallback);
  }

  // This test that a MediaStream can be cloned and that the clone can
  // be rendered.
  function getUserMediaAndClone() {
    console.log('Calling getUserMediaAndClone.');
    navigator.webkitGetUserMedia({video: true, audio: true},
        createAndRenderClone, failedCallback);
  }

  // Creates two MediaStream and renders them locally. When the video of both
  // streams are detected to be rolling, we stop the local video tracks one at
  // the time.
  function twoGetUserMediaAndStop(constraints) {
    console.log('Calling Two GetUserMedia');
    navigator.webkitGetUserMedia(
        constraints,
        function(stream) {
          displayAndDetectVideo(stream, requestSecondGetUserMedia);
        },
        failedCallback);
    var requestSecondGetUserMedia = function() {
      navigator.webkitGetUserMedia(
          constraints,
          function(stream) {
            displayIntoVideoElement(stream,
                                    function() {
                                      stopBothVideoTracksAndVerify(stream);
                                    },
                                    'local-view-2');
          },
          failedCallback);
    };

    var stopBothVideoTracksAndVerify = function(streamPlayingInLocalView2) {
      streamPlayingInLocalView2.getVideoTracks()[0].stop();
      waitForVideoToStop('local-view-2');
      // Make sure the video track in gLocalStream is still playing in
      // 'local-view1' and then stop it.
      displayAndDetectVideo(gLocalStream, stopVideoTrack);
    };
  }

  function twoGetUserMedia(constraints1, constraints2) {
    console.log('Calling Two GetUserMedia');
    var result="";
    navigator.webkitGetUserMedia(
        constraints1,
        function(stream) {
          displayDetectAndAnalyzeVideoInElement(
              stream,
              function(aspectRatio) {
                result = aspectRatio;
                requestSecondGetUserMedia();
              },
              'local-view');
        },
        failedCallback);
    var requestSecondGetUserMedia = function() {
      navigator.webkitGetUserMedia(
          constraints2,
          function(stream) {
            displayDetectAndAnalyzeVideoInElement(
                stream,
                function(aspectRatio) {
                  result = result + '-' + aspectRatio;
                  sendValueToTest(result);
                },
                'local-view-2');
          },
          failedCallback);
    }
  }

  function failedCallback(error) {
    failTest('GetUserMedia call failed with code ' + error.code);
  }

  function plugStreamIntoVideoElement(stream, videoElement) {
    gLocalStream = stream;
    var localStreamUrl = URL.createObjectURL(stream);
    $(videoElement).src = localStreamUrl;
  }

  function displayIntoVideoElement(stream, callback, videoElement) {
    plugStreamIntoVideoElement(stream, videoElement);
    detectVideoPlaying(videoElement, callback);
  }

  function displayAndDetectVideo(stream, callback) {
    displayIntoVideoElement(stream, callback, 'local-view');
  }

  function displayDetectAndAnalyzeVideo(stream) {
    displayDetectAndAnalyzeVideoInElement(stream,
        function(aspectRatio) {
          sendValueToTest(aspectRatio);
        },
        'local-view');
  }

  function displayDetectAndAnalyzeVideoInElement(
      stream, callback, videoElement) {
    plugStreamIntoVideoElement(stream, videoElement);
    detectAspectRatio(callback, videoElement);
  }

  function createAndRenderClone(stream) {
    gLocalStream = stream;
    // TODO(perkj):  --use-fake-device-for-media-stream do not currently
    // work with audio devices and not all bots has a microphone.
    new_stream = new webkitMediaStream();
    new_stream.addTrack(stream.getVideoTracks()[0]);
    assertEquals(new_stream.getVideoTracks().length, 1);
    if (stream.getAudioTracks().length > 0) {
      new_stream.addTrack(stream.getAudioTracks()[0]);
      assertEquals(new_stream.getAudioTracks().length, 1);
      new_stream.removeTrack(new_stream.getAudioTracks()[0]);
      assertEquals(new_stream.getAudioTracks().length, 0);
    }

    var newStreamUrl = URL.createObjectURL(new_stream);
    $('local-view').src = newStreamUrl;
    waitForVideo('local-view');
  }

  function stopVideoTrack() {
    gLocalStream.getVideoTracks()[0].stop();
    waitForVideoToStop('local-view');
  }

  function waitAndStopVideoTrack(waitTimeInSeconds) {
    setTimeout(stopVideoTrack, waitTimeInSeconds * 1000);
  }

  // This test make sure multiple video renderers can be created for the same
  // local video track and make sure a renderer can still render if other
  // renderers are paused. See http://crbug/352619.
  function createMultipleVideoRenderersAndPause(stream) {
    function createDetectableRenderer(stream, id) {
      var video = document.createElement('video');
      document.body.appendChild(video);
      var localStreamUrl = URL.createObjectURL(stream);
      video.id = id;
      video.src = localStreamUrl;
      video.autoplay = true;
      video.play();
      // The detector needs a canvas.
      var canvas = document.createElement('canvas');
      canvas.id = video.id + "-canvas";
      document.body.appendChild(canvas);
    };

    // Once 3 renderers are created and paused, create one last renderer and
    // make sure it can play video.
    setAllEventsOccuredHandler(function() {
      var id = "lastVideoTag";
      createDetectableRenderer(stream, id);
      detectVideoPlaying(id, function () { reportTestSuccess(); });
    });

    // Create 3 video renderers and pause them once video is playing.
    for (var i = 0; i < 3; ++i) {
      var id = "video" + i;
      createDetectableRenderer(stream, id);
      addExpectedEvent();
      // |video_detected_function| creates a new function that pause the video
      // tag |id|.
      var video_detected_function =
          function (j) {
            return function () {
              console.log("pause " + j);
              $(j).pause();
              eventOccured();
           };
          };
      // Detect video id |id| and trigger the function returned by
      // |video_detected_function| when video is playing.
      detectVideoPlaying(id, video_detected_function(id));
     }
   }

  // This function tries to calculate the aspect ratio shown by the fake capture
  // device in the video tag. For this, we count the amount of light green
  // pixels along |aperture| pixels on the positive X and Y axis starting from
  // the center of the image. In this very center there should be a time-varying
  // pacman; the algorithm counts for a couple of iterations and keeps the
  // maximum amount of light green pixels on both directions. From this data
  // the aspect ratio is calculated and the test fails if the number of green
  // pixels are not the same along the X and Y axis.
  // The result of the analysis is sent back to the test as a string on the
  // format "w=xxx:h=yyy".
  function detectAspectRatio(callback, videoElementName) {
    var videoElement = $(videoElementName);
    var canvas = $(videoElementName + '-canvas');

    var maxLightGreenPixelsX = 0;
    var maxLightGreenPixelsY = 0;

    var iterations = 0;
    var maxIterations = 10;

    var detectorFunction = function() {
      var width = videoElement.videoWidth;
      var height = videoElement.videoHeight;
      if (width == 0 || height == 0)
        return;

      canvas.width = width;
      canvas.height = height;
      var aperture = Math.min(width, height) / 2;
      var context = canvas.getContext('2d');
      context.drawImage(videoElement, 0, 0, width, height);

      // We are interested in a window starting from the center of the image
      // where we expect the circle from the fake video capture to be rolling.
      var pixels = context.getImageData(width / 2, height / 2,
                                        aperture, aperture);

      var lightGreenPixelsX = 0;
      var lightGreenPixelsY = 0;

      // Walk horizontally counting light green pixels.
      for (var x = 0; x < aperture; ++x) {
        if (pixels.data[4 * x + 1] != COLOR_BACKGROUND_GREEN)
          lightGreenPixelsX++;
      }
      // Walk vertically counting light green pixels.
      for (var y = 0; y < aperture; ++y) {
        if (pixels.data[4 * y * aperture + 1] != COLOR_BACKGROUND_GREEN)
          lightGreenPixelsY++;
      }
      if (lightGreenPixelsX > maxLightGreenPixelsX)
        maxLightGreenPixelsX = lightGreenPixelsX;
      if (lightGreenPixelsY > maxLightGreenPixelsY)
        maxLightGreenPixelsY = lightGreenPixelsY;

      if (++iterations > maxIterations) {
        clearInterval(detectorInterval);
        // Allow maxLightGreenPixelsY = maxLightGreenPixelsX +-1 due to
        // possible subpixel rendering on Mac and Android.
        if (maxLightGreenPixelsY > maxLightGreenPixelsX + 1 ||
            maxLightGreenPixelsY < maxLightGreenPixelsX -1 ||
            maxLightGreenPixelsY == 0 ||
            maxLightGreenPixelsX == width || maxLightGreenPixelsY == height) {
          failTest("Aspect ratio corrupted. X " + maxLightGreenPixelsX  +
            " Y " + maxLightGreenPixelsY);
        }

        var result = "w=" + width + ":h=" + height;
        console.log(result);
        callback(result);
      }
    }
    var detectorInterval = setInterval(detectorFunction, 50);
  }
  </script>
</head>
<body>
  <table border="0">
    <tr>
      <td>Local Preview</td>
    </tr>
    <tr>
      <td><video width="320" height="240" id="local-view"
          autoplay="autoplay"></video></td>
      <td><canvas id="local-view-canvas"
          style="display:none"></canvas></td>
    </tr>
    <tr>
      <td>Local Preview 2</td>
    </tr>
    <tr>
      <td><video width="320" height="240" id="local-view-2"
          autoplay="autoplay"></video></td>
      <!-- Canvases are named after their corresponding video elements. -->
      <td><canvas width="320" height="240" id="local-view-2-canvas"
          style="display:none"></canvas></td>
    </tr>
  </table>
</body>
</html>