chromium/third_party/blink/web_tests/webaudio/internals/stopped-source-test.js

// Test GC of disconnected and stopped source nodes
function testStoppedSourceGC(task, should, options) {
  let {context, nodeName, constructorMethod, numberOfNodes} = options;
  let countEndedNodes = 0;
  let gain = new GainNode(context, {gain: 1e-10});
  gain.connect(context.destination);

  // When |lastSrc0| stops, it will run gc.
  let lastSrc0 = new ConstantSourceNode(context);
  lastSrc0.connect(gain);

  // When |lastSrc1| stops, we'll verify that the number of handlers left
  // is correct.
  let lastSrc1 = new ConstantSourceNode(context);
  lastSrc1.connect(gain);

  lastSrc0.onended = () => {
    asyncGC().then(function () {
      // Have |lastSrc1| stop 10 render quanta from now (pretty arbitrary).
      lastSrc1.stop(
        context.currentTime + 10 * RENDER_QUANTUM_FRAMES / context.sampleRate);
    });
  };

  lastSrc1.onended = () => {
    // All the disconnected sources should have been collected by now.
    should(internals.audioHandlerCount(), 'Number of handlers after GC')
      .beEqualTo(initialCount);
    task.done();
  };

  let initialCount = 0;
  asyncGC().then(function () {
    initialCount = internals.audioHandlerCount();

    // For information only.  This should obviously always pass.
    should(initialCount, 'Number of handlers before test')
        .beEqualTo(initialCount);
    // Create a bunch of sources for testing.  Since we call stop(), these
    // should all get collected, even though they're no longer connected to
    // the destination.
    for (let k = 0; k < numberOfNodes; ++k) {
      let src = constructorMethod();
      src.start();
      src.connect(gain);
      src.onended = () => {
        ++countEndedNodes;
        if (countEndedNodes == numberOfNodes) {
          // For information only
          should(countEndedNodes, `Number of ${nodeName}s tested`)
              .beEqualTo(numberOfNodes);
          lastSrc0.stop();
        }
      };
      // Stop it after about 2 renders
      src.stop(
          context.currentTime + 2 * RENDER_QUANTUM_FRAMES / context.sampleRate);
      src.disconnect();
    }

    // Start the sources
    lastSrc0.start();
    lastSrc1.start();
  });
}