<!DOCTYPE html>
<html>
  <head>
    <title>
      automatic-pull-node.html
    </title>
    <script src="../../imported/w3c/web-platform-tests/resources/testharness.js"></script>
    <script src="../../resources/testharnessreport.js"></script>
    <script src="../resources/audit-util.js"></script>
    <script src="../resources/audit.js"></script>
  </head>
  <body>
    <script id="layout-test-code">
      // This test verifies that the AudioBasicInspectorNode based nodes work
      // correctly

      let audit = Audit.createTaskRunner();

      let sampleRate = 44100.0;
      // We carefully arrange the renderLengthInFrames to be a multiple of the
      // AudioNode rendering quantum (AudioNode::ProcessingSizeInFrames) so that
      // AudioSourceNode will not feed tailing zeroes into the context and fail
      // this test.
      let renderLengthInFrames = 256;
      let fftSize = 64;

      let audioDataOne = 255;   // Audio data 1.0 in Uint8 format will be 255.
      let audioDataZero = 128;  // Audio data 0 in Uint8 format will be 128.

      let context;
      let constantBuffer;
      let bufferSource;
      let analyser;

      function constructCommonGraph() {
        // Create offline audio context.
        context = new OfflineAudioContext(1, renderLengthInFrames, sampleRate);
        constantBuffer = createConstantBuffer(context, renderLengthInFrames, 1);

        bufferSource = context.createBufferSource();
        bufferSource.buffer = constantBuffer;

        analyser = context.createAnalyser();
        analyser.fftSize = fftSize;

        bufferSource.connect(analyser);
      }

      function test1Finished(should) {
        let timeDomainData = new Uint8Array(fftSize);
        analyser.getByteTimeDomainData(timeDomainData);

        should(
            timeDomainData[0] >= audioDataOne,
            'RealtimeAnalyserNode got pulled when connected from upstream node but not to downstream node')
            .beTrue();
      }

      // To verify the realtimeAnalyser can pull data when there is an upstream
      // node connected to it but it's not connected to a downstream node.
      audit.define('test1', function(task, should) {
        constructCommonGraph();

        bufferSource.start(0);

        context.startRendering()
            .then(function() {
              test1Finished(should);
            })
            .then(task.done.bind(task));
      });

      function test2Finished(should) {
        let timeDomainData = new Uint8Array(fftSize);
        analyser.getByteTimeDomainData(timeDomainData);

        should(
            timeDomainData[0] >= audioDataOne,
            'RealtimeAnalyserNode got pulled when connected from upstream node and to destination node')
            .beTrue();
      }

      // To verify the realtimeAnalyser can process normally when there is an
      // upstream node connected to it and it's also connected to a downstream
      // node which ultimately connect to audio destination.
      audit.define('test2', function(task, should) {
        constructCommonGraph();

        analyser.connect(context.destination);

        bufferSource.start(0);

        context.startRendering()
            .then(function() {
              test2Finished(should);
            })
            .then(task.done.bind(task));
      });

      function test3Finished(should) {
        let timeDomainData = new Uint8Array(fftSize);
        analyser.getByteTimeDomainData(timeDomainData);

        // If realtimeAnalyser hasn't pulled any data, the data in buffer will
        // be 0.
        should(
            timeDomainData[0] == audioDataZero,
            'RealtimeAnalyserNode didn\'t get pulled when it should not')
            .beTrue();
        ;
      }

      // To verify the realtimeAnalyser will stop pulling if it is connected to
      // a downstream node which is not ultimatly connected to any audio
      // destination.
      audit.define('test3', function(task, should) {
        constructCommonGraph();

        let gain = context.createGain();
        analyser.connect(gain);

        bufferSource.start(0);

        context.startRendering()
            .then(function() {
              test3Finished(should);
            })
            .then(task.done.bind(task));
      });

      audit.run();
    </script>
  </body>
</html>
