chromium/third_party/blink/web_tests/webaudio/AudioBufferSource/audiobuffersource-premature-loop-stop.html

<!DOCTYPE html>
<html>
  <head>
    <title>
      Test AudioBufferSourceNode premature loop stop
    </title>
    <script src="../../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">
      // Reasonably low sample rate for the optimum test speed.
      let sampleRate = 8192;

      let audit = Audit.createTaskRunner();

      // Task: Create a buffer with 3 regions filled with constant value of [1,
      // 2, 3]. Then set a loop range over the second region. Start the loop and
      // disable it in the middle of looping. Verify the rendered buffer has the
      // entire content including the looped region.
      audit.define('premature-loop-stop', (task, should) => {
        let regionValues = [1, 2, 3];

        // The region length is 2 * render quantum size to be able to suspend
        // the rendering at the half of the region.
        let regionLength = 256;

        // The test will repeat the second region 3 times, thus the rendered
        // audio have the length of 5 * regionLength.
        let context = new OfflineAudioContext(1, 5 * regionLength, sampleRate);

        // Create 3 constant buffers of [1, 2, 3] and concatenate them together:
        // | 1 | 2 | 3 |
        let testBuffer = context.createBuffer(1, 3 * regionLength, sampleRate);
        let testChannel = testBuffer.getChannelData(0);
        for (let i = 0; i < regionValues.length; i++) {
          let region =
              createConstantBuffer(context, regionLength, regionValues[i]);
          testChannel.set(region.getChannelData(0), regionLength * i);
          ;
        }

        let source = context.createBufferSource();
        source.connect(context.destination);

        source.buffer = testBuffer;
        source.loop = true;

        // Set loop points over the region 2.
        source.loopStart = regionLength / sampleRate;
        source.loopEnd = 2 * regionLength / sampleRate;

        source.start();

        // Disengage the loop at |3.5 * regionLength / sampleRate| which is the
        // end of 7th rendering quantum and also the half of the third iteration
        // of region #2.
        context.suspend(3.5 * regionLength / sampleRate).then(function() {
          source.loop = false;
          context.resume();
        });

        context.startRendering()
            .then(function(renderedBuffer) {
              let channel = renderedBuffer.getChannelData(0);

              // Verify if the rendered buffer has the following structure:
              // | 1 | 2 | 2 | 2 | 3 |
              let region1 = channel.subarray(0, regionLength - 1);
              let region2 =
                  channel.subarray(regionLength, 4 * regionLength - 1);
              let region3 =
                  channel.subarray(4 * regionLength, 5 * regionLength - 1);

              should(region1, 'Region #1').beConstantValueOf(1);
              should(region2, 'Region #2 (looped)').beConstantValueOf(2);
              should(region3, 'Region #3').beConstantValueOf(3);
            })
            .then(() => task.done());
      });

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