<!DOCTYPE html>
<html>
<head>
<title>
offlineaudiocontext-suspend-resume-basic.html
</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">
let sampleRate = 44100;
let renderDuration = 1;
let renderQuantum = 128;
let audit = Audit.createTaskRunner();
// Task: Calling suspend with no argument, negative time or the time
// beyond the maximum render duration reject the promise.
audit.define('suspend-invalid-argument', (task, should) => {
let context =
new OfflineAudioContext(1, sampleRate * renderDuration, sampleRate);
should(context.suspend(), 'context.suspend()').beRejected();
should(context.suspend(-1.0), 'context.suspend(-1.0)').beRejected();
should(context.suspend(2.0), 'context.suspend(2.0)').beRejected();
context.startRendering().then(() => task.done());
});
// Task: Scheduling a suspend in the past should be rejected.
audit.define('suspend-in-the-past', (task, should) => {
let context =
new OfflineAudioContext(1, sampleRate * renderDuration, sampleRate);
context.suspend(0.5).then(function() {
should(
context.suspend(context.currentTime - 0.1),
'Scheduling a suspend in the past')
.beRejected();
should(context
.suspend(
context.currentTime + 0.1,
'Scheduling a suspend in the future')
.then(function() {
context.resume();
}))
.beResolved();
context.resume();
});
context.startRendering().then(() => task.done());
});
// Task: suspending after rendering is finished must be rejected with the
// properly clamped frame/time information.
audit.define('suspend-after-render-completion', (task, should) => {
let context =
new OfflineAudioContext(1, sampleRate * renderDuration, sampleRate);
context.startRendering()
.then(function() {
should(
context.suspend(renderDuration),
'Scheduling a suspend after the render completion')
.beRejected();
})
.then(() => task.done());
});
// Task: Calling multiple suspends at the same rendering quantum should
// reject the promise.
audit.define('identical-suspend-time', (task, should) => {
let context =
new OfflineAudioContext(1, sampleRate * renderDuration, sampleRate);
// |suspendTime1| and |suspendTime2| are identical when quantized to the
// render quantum size. The factors are arbitrary except they should be
// between 1 (exclusive) and 2 (inclusive). Using a factor of 2 also
// tests that times are rounded up.
let suspendTime1 = 1.25 * renderQuantum / sampleRate;
let suspendTime2 = 2 * renderQuantum / sampleRate;
should(
() => context.suspend(suspendTime1).then(() => context.resume()),
'Scheduling a suspend at frame ' + suspendTime1 * sampleRate)
.notThrow();
should(
context.suspend(suspendTime2).then(() => context.resume()),
'Scheduling another suspend at the same rendering quantum')
.beRejected();
context.startRendering().then(() => task.done());
});
// Task: Resuming a running context should be resolved.
audit.define('resume-before-suspend', (task, should) => {
// Make the render length 5 times longer to minimize the flakiness.
let longRenderDuration = renderDuration * 5;
let context = new OfflineAudioContext(
1, sampleRate * longRenderDuration, sampleRate);
// Create dummy audio graph to slow the rendering.
let osc = context.createOscillator();
let lpf = context.createBiquadFilter();
osc.type = 'sawtooth';
osc.frequency.setValueAtTime(0.1, 0.0);
osc.frequency.linearRampToValueAtTime(1000, longRenderDuration * 0.5);
osc.frequency.linearRampToValueAtTime(0.1, longRenderDuration);
lpf.frequency.setValueAtTime(0.1, 0.0);
lpf.frequency.linearRampToValueAtTime(1000, longRenderDuration * 0.5);
lpf.frequency.linearRampToValueAtTime(0.1, longRenderDuration);
osc.connect(lpf);
lpf.connect(context.destination);
osc.start();
// A suspend is scheduled at the 90% of the render duration.
should(
() => {
// Test is finished when this suspend resolves.
context.suspend(longRenderDuration * 0.9).then(() => task.done());
},
'Scheduling a suspend at ' + longRenderDuration * 0.9 + ' seconds')
.notThrow();
// We have to start rendering to get the time running.
context.startRendering();
// Then call resume() immediately after the rendering starts. Resuming
// a context that is already running should be resolved.
should(context.resume(), 'Resuming a running context').beResolved();
});
// Task: Calling resume on a context that is not started should reject the
// promise.
audit.define('resume-without-suspend', (task, should) => {
let context =
new OfflineAudioContext(1, sampleRate * renderDuration, sampleRate);
should(context.resume(), 'Resuming a context without starting it')
.beRejected()
.then(() => task.done());
});
audit.run();
</script>
</body>
</html>