<!DOCTYPE html>
<html>
  <head>
    <title>
      Test Automation of AudioListener
    </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">
      let sampleRate = 48000;
      // These tests are quite slow, so don't run for many frames.  1024 frames
      // should be enough to demonstrate that automations are working.
      let renderFrames = 1024;
      let renderDuration = renderFrames / sampleRate;

      // End time of the automation.  Fairly arbitrary, but must be less than
      // the render duration so that we can verify that the automation did end
      // at the correct time and value.
      let endTime = 0.75 * renderDuration;

      let audit = Audit.createTaskRunner();

      // Starting position for the panner
      let defaultStartPosition = {x: 0, y: 0, z: 0};

      // Ending position for the panner
      let pannerEndPosition = {x: 1000, y: 1000, z: 1000};

      // Ending position for the listener.  It MUST be the the negative of the
      // pannerEndPosition!
      let listenerEndPosition = {
        x: -pannerEndPosition.x,
        y: -pannerEndPosition.y,
        z: -pannerEndPosition.z
      };


      // Test the linear, inverse, and exponential distance models when the
      // AudioListener is moving instead of the panner.  We take advantage that
      // motion is relative and create a reference by moving the panner in one
      // direction.  The resulting output is the expected result.  Then we redo
      // the test, but this time move the listener in the opposite direction.
      // The output of this test is compared against the panner result.  They
      // should be the same.

      audit.define('linear', (task, should) => {
        runTest({
          should: should,
          startPosition: defaultStartPosition,
          endPosition: pannerEndPosition,
          distanceModel: {model: 'linear', rolloff: 1}
        }).then(() => task.done());
      });

      audit.define('exponential', (task, should) => {
        runTest({
          should: should,
          startPosition: defaultStartPosition,
          endPosition: pannerEndPosition,
          distanceModel: {model: 'exponential', rolloff: 1.5}
        }).then(() => task.done());
      });

      audit.define('inverse', (task, should) => {
        runTest({
          should: should,
          startPosition: defaultStartPosition,
          endPosition: pannerEndPosition,
          distanceModel: {model: 'inverse', rolloff: 1}
        }).then(() => task.done());
      });

      audit.run();

      function createGraph() {
        let context = new OfflineAudioContext(2, renderFrames, sampleRate);
        // Stereo source for the panner.
        let source = context.createBufferSource();
        source.buffer = createConstantBuffer(context, renderFrames, [1, 2]);

        let panner = context.createPanner();
        panner.panningModel = 'equalpower';

        source.connect(panner);
        panner.connect(context.destination);

        return {context: context, source: source, panner: panner};
      }

      // Run a listener test with the given options.
      function runTest(options) {
        let refResult;

        return runPannerTest(options)
            .then(function(renderedBuffer) {
              refResult = renderedBuffer;
            })
            .then(function() {
              // Move the listener in the opposite direction.
              options.endPosition = listenerEndPosition;
              return runListenerTest(options).then(function(renderedBuffer) {
                compareResults(renderedBuffer, refResult, options);
              });
            });
      }

      function runPannerTest(options) {
        let graph = createGraph();

        return runTestCore(graph, options, graph.panner);
      }


      function runListenerTest(options) {
        let graph = createGraph();

        return runTestCore(graph, options, graph.context.listener);
      }

      function runTestCore(graph, options, audioOjbect) {
        let {context, source, panner} = graph;

        // Initialize the panner with known values.
        panner.distanceModel = options.distanceModel.model;
        panner.rolloffFactor = options.distanceModel.rolloff;
        panner.panningModel = 'equalpower';

        // Automate the location.  audioObject must be either a PannerNode or
        // the context's AudioListener.

        audioOjbect.positionX.setValueAtTime(options.startPosition.x, 0);
        audioOjbect.positionY.setValueAtTime(options.startPosition.y, 0);
        audioOjbect.positionZ.setValueAtTime(options.startPosition.z, 0);

        audioOjbect.positionX.linearRampToValueAtTime(
            options.endPosition.x, endTime);
        audioOjbect.positionY.linearRampToValueAtTime(
            options.endPosition.y, endTime);
        audioOjbect.positionZ.linearRampToValueAtTime(
            options.endPosition.z, endTime);

        // Start the source, render the graph, and return the resulting promise
        // from rendering.
        source.start();

        return context.startRendering().then(function(resultBuffer) {
          return resultBuffer;
        });
      }

      function compareResults(actualResult, expectedResult, options) {
        // Compare the output with the reference output from moving the source
        // in the opposite direction.

        let expectedLeft = expectedResult.getChannelData(0);
        let expectedRight = expectedResult.getChannelData(1);

        let actualLeft = actualResult.getChannelData(0);
        let actualRight = actualResult.getChannelData(1);

        let prefix = 'Distance model: "' + options.distanceModel.model + '"';
        prefix += ', rolloff: ' + options.distanceModel.rolloff;
        options.should(actualLeft, prefix + ': left channel')
            .beCloseToArray(expectedLeft, 0);
        options.should(actualRight, prefix + ': right channel')
            .beCloseToArray(expectedRight, 0);
      }
    </script>
  </body>
</html>
