<!DOCTYPE html>
<html>
  <head>
    <title>
      offlineaudiocontext-suspend-resume-graph-manipulation.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">
      let audit = Audit.createTaskRunner();

      let context;
      let renderQuantum = 128;
      let renderDuration = 3;

      // The sample rate is multiple of the rendering quantum, so suspension
      // times fall in to the render quantum boundary.
      let sampleRate = renderQuantum * 100;

      // Suspend at 1 second and activate the source node. The audio output
      // should be 1.0 from |suspendTime1| to the next suspension.
      let suspendTime1 = 1;

      // Suspend at 2 seconds and disconnect the node. The audio output should
      // be 0.0 from |suspendTime2| to the end.
      let suspendTime2 = 2;

      audit.define(
          {
            label: 'test',
            description:
                'Synchronous graph manipulation with suspend() and resume()'
          },
          (task, should) => {
            context = new OfflineAudioContext(
                1, sampleRate * renderDuration, sampleRate);

            // Create a constant buffer of 1.0.
            let constantBuffer = createConstantBuffer(context, 1, 1.0);
            let constantSource = context.createBufferSource();
            constantSource.buffer = constantBuffer;
            constantSource.loop = true;

            // The audio output from the beginning (0.0 second) to the first
            // suspend time should be 0.0 because there is no connection to the
            // destination.

            context.suspend(suspendTime1).then(function() {
              if (context.currentTime === suspendTime1) {
                should(
                    context.currentTime * sampleRate,
                    'Frame at which context is suspended')
                    .beEqualTo(suspendTime1 * sampleRate)
              }
              should(
                  () => {
                    constantSource.connect(context.destination);
                    constantSource.start()
                  },
                  'Connecting a constant buffer to destination and starting at ' +
                      suspendTime1 * sampleRate + ' frame')
                  .notThrow();
              ;
              context.resume();
            });

            context.suspend(suspendTime2).then(function() {
              if (context.currentTime === suspendTime2) {
                should(context.currentTime * sampleRate, 'Context is suspended')
                    .beEqualTo(suspendTime2 * sampleRate);
              }
              should(
                  () => constantSource.disconnect(),
                  'Disconnecting a constant buffer at ' +
                      suspendTime2 * sampleRate + ' frame')
                  .notThrow();

              context.resume();
            });

            context.startRendering()
                .then(function(buffer) {
                  verifyResult(should, buffer);
                })
                .then(() => task.done());
          });

      function verifyResult(should, buffer) {
        let data = buffer.getChannelData(0);

        let suspendIndex1 = suspendTime1 * sampleRate;
        let suspendIndex2 = suspendTime2 * sampleRate;
        let endIndex = renderDuration * sampleRate;

        // Split the rendered buffer into 3 segments:
        // [0, suspendIndex1), [suspendIndex1, suspendIndex2), [suspendIndex2,
        // endIndex).
        let subarray0 = data.subarray(0, suspendIndex1);
        let subarray1 = data.subarray(suspendIndex1, suspendIndex2);
        let subarray2 = data.subarray(suspendIndex2, endIndex);

        // Each segment should contain a constant value of 0, 1 and 0
        // respectively.
        should(subarray0, 'Buffer frame [0, ' + suspendIndex1 + ')')
            .beConstantValueOf(0);
        should(
            subarray1,
            'Buffer frame [' + suspendIndex1 + ', ' + suspendIndex2 + ')')
            .beConstantValueOf(1);
        should(
            subarray2, 'Buffer frame [' + suspendIndex2 + ', ' + endIndex + ')')
            .beConstantValueOf(0);
      }

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