<!doctype html>
<meta charset=utf-8>
<meta name="timeout" content="long">
<title>RTCPeerConnection Video detector test</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="RTCPeerConnection-helper.js"></script>
<script>
'use strict';

// This test verifies that the helper function "detectSignal" from
// RTCPeerConnectionHelper, which is used to detect changes in a video
// signal, performs properly for a range of "signal" values.

// If it fails, it indicates that the video codec used in this particular
// browser at this time doesn't reproduce the luma signal reliably enough
// for this particular application, which may lead to other tests that
// use the "detectSignal" helper failing without an obvious cause.

// The most likely failure is timeout - which will happen if the
// luma value detected doesn't settle within the margin of error before
// the test times out.

async function signalSettlementTime(t, v, sender, signal, backgroundTrack) {
  const detectionStream = await getNoiseStream({video: {signal}});
  const [detectionTrack] = detectionStream.getTracks();
  try {
    await sender.replaceTrack(detectionTrack);
    const framesBefore = v.getVideoPlaybackQuality().totalVideoFrames;
    await detectSignal(t, v, signal);
    const framesAfter = v.getVideoPlaybackQuality().totalVideoFrames;
    await sender.replaceTrack(backgroundTrack);
    await detectSignal(t, v, 100);
    return framesAfter - framesBefore;
  } finally {
    detectionTrack.stop();
  }
}

promise_test(async t => {
  const v = document.createElement('video');
  v.autoplay = true;
  const pc1 = new RTCPeerConnection();
  const pc2 = new RTCPeerConnection();
  t.add_cleanup(() => pc1.close());
  t.add_cleanup(() => pc2.close());
  const stream1 = await getNoiseStream({video: {signal: 100}});
  const [track1] = stream1.getTracks();
  t.add_cleanup(() => track1.stop());

  const sender = pc1.addTrack(track1);
  const haveTrackEvent = new Promise(r => pc2.ontrack = r);
  exchangeIceCandidates(pc1, pc2);
  await exchangeOfferAnswer(pc1, pc2);
  v.srcObject = new MediaStream([(await haveTrackEvent).track]);
  await new Promise(r => v.onloadedmetadata = r);
  // The basic signal is a track with signal 100. We replace this
  // with tracks with signal from 0 to 255 and see if they are all
  // reliably detected.
  await detectSignal(t, v, 100);
  // A few buffered frames are received with the old content, and a few
  // frames may not have settled on exactly the right value. In testing,
  // this test passes with maxFrames = 3; give a little more margin.
  const maxFrames = 7;
  // Test values 0 and 255
  let maxCount = await signalSettlementTime(t, v, sender, 0, track1);
  assert_less_than(maxCount, maxFrames,
      'Should get the black value within ' + maxFrames + ' frames');
  maxCount = Math.max(
      await signalSettlementTime(t, v, sender, 255, track1), maxCount);
  assert_less_than(maxCount, maxFrames,
      'Should get the white value within ' + maxFrames + ' frames');
  // Test a set of other values - far enough apart to make the test fast.
  for (let signal = 2; signal <= 255; signal += 47) {
    if (Math.abs(signal - 100) > 10) {
      const count = await signalSettlementTime(t, v, sender, signal, track1);
      maxCount = Math.max(count, maxCount);
      assert_less_than(maxCount, 10,
          'Should get value ' + signal + ' within ' + maxFrames + ' frames');
    }
  }
  assert_less_than(maxCount, 10, 'Should get the right value within 10 frames');
}, 'Signal detector detects track change within reasonable time');
</script>
