<!DOCTYPE html>
<html>
<head>
<title>
Test premature GC upon OscillatorNode and AudioBufferSourceNode
</title>
<script src="../../resources/gc.js"></script>
<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">
let sampleRate = 44100;
let renderDuration = 1;
let audit = Audit.createTaskRunner();
// Create a graph for testing in an isolated scope. Returns |context|.
// Create two nodes and schedule only one of them. Then check if |onended|
// from the scheduled node is fired correctly.
function createGraphInIsolatedScope(sourceNodeType, task, should) {
'use strict';
let context =
new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
{
let node = context['create' + sourceNodeType]();
node.connect(context.destination);
if (sourceNodeType === 'BufferSource') {
let emptyBuffer = context.createBuffer(1, sampleRate, sampleRate);
node.buffer = emptyBuffer;
}
// If the node is GCed, |onended| won't be fired. Then this test
// will be timed out because done() will not get called.
node.onended = () => {
should(
true,
sourceNodeType + 'Node 1 survived GC and onended event fired')
.beEqualTo(true);
task.done();
};
node.start();
node.stop(0.5 * renderDuration);
}
// Suspend and GC before the render finishes. The time position is
// arbitrary. GC should collect |osc2| because it is not scheduled.
context.suspend(0.1 * renderDuration).then(async () => {
await asyncGC();
context.resume();
});
context.startRendering();
}
audit.define('oscillator-onended', (task, should) => {
createGraphInIsolatedScope('Oscillator', task, should);
});
audit.define('buffersource-onended', (task, should) => {
createGraphInIsolatedScope('BufferSource', task, should);
});
audit.run();
</script>
</body>
</html>