<!doctype html>
<html>
  <head>
    <title>Test Flushing of NaN to Zero in AudioParams</title>
    <script src="/resources/testharness.js"></script>
    <script src="/resources/testharnessreport.js"></script>
    <script src="/webaudio/resources/audit-util.js"></script>
    <script src="/webaudio/resources/audit.js"></script>
  </head>

  <body>
    <script>
      let audit = Audit.createTaskRunner();

      // See
      // https://webaudio.github.io/web-audio-api/#computation-of-value.
      //
      // The computed value must replace NaN values in the output with
      // the default value of the param.
      audit.define('AudioParam NaN', async (task, should) => {
        // For testing, we only need a small number of frames; and
        // a low sample rate is perfectly fine.  Use two channels.
        // The first channel is for the AudioParam output.  The
        // second channel is for the AudioParam input.
        let context = new OfflineAudioContext(
            {numberOfChannels: 2, length: 256, sampleRate: 8192});
        let merger = new ChannelMergerNode(
            context, {numberOfInputs: context.destination.channelCount});
        merger.connect(context.destination);

        // A constant source with a huge value.
        let mod = new ConstantSourceNode(context, {offset: 1e30});

        // Gain nodes with a huge positive gain and huge negative
        // gain.  Combined with the huge offset in |mod|, the
        // output of the gain nodes are +Infinity and -Infinity.
        let gainPos = new GainNode(context, {gain: 1e30});
        let gainNeg = new GainNode(context, {gain: -1e30});

        mod.connect(gainPos);
        mod.connect(gainNeg);

        // Connect these to the second merger channel. This is a
        // sanity check that the AudioParam input really is NaN.
        gainPos.connect(merger, 0, 1);
        gainNeg.connect(merger, 0, 1);

        // Source whose AudioParam is connected to the graph
        // that produces NaN values.  Use a non-default value offset
        // just in case something is wrong we get default for some
        // other reason.
        let src = new ConstantSourceNode(context, {offset: 100});

        gainPos.connect(src.offset);
        gainNeg.connect(src.offset);

        // AudioParam output goes to channel 1 of the destination.
        src.connect(merger, 0, 0);

        // Let's go!
        mod.start();
        src.start();

        let buffer = await context.startRendering();

        let input = buffer.getChannelData(1);
        let output = buffer.getChannelData(0);

        // Have to test manually for NaN values in the input because
        // NaN fails all comparisons.
        let isNaN = true;
        for (let k = 0; k < input.length; ++k) {
          if (!Number.isNaN(input[k])) {
            isNaN = false;
            break;
          }
        }

        should(isNaN, 'AudioParam input contains only NaN').beTrue();

        // Output of the AudioParam should have all NaN values
        // replaced by the default.
        should(output, 'AudioParam output')
            .beConstantValueOf(src.offset.defaultValue);

        task.done();
      });

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