Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!doctype html>
<title>Test AudioContext state updates with suspend() shortly after
construction</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
// A separate async_test is used for tracking state change counts so that it
// can report excess changes after the promise_test for the iteration has
// completed.
const changeCountingTest = async_test('State change counting');
const doTest = async (testCount) => {
const ctx = new AudioContext();
// Explicitly resume to get a promise to indicate whether the context
// successfully started running.
const resume = ctx.resume();
const suspend = ctx.suspend();
let stateChangesDone = new Promise((resolve) => {
ctx.onstatechange = () => {
++ctx.stateChangeCount;
changeCountingTest.step(() => {
assert_less_than_equal(ctx.stateChangeCount,
ctx.expectedStateChangeCount,
`ctx ${testCount} state change count.`);
assert_equals(ctx.state, ctx.expectedState, `ctx ${testCount} state`);
});
if (ctx.stateChangeCount == ctx.totalStateChangeCount) {
resolve();
}
};
});
ctx.stateChangeCount = 0;
ctx.expectedStateChangeCount = 1;
ctx.expectedState = 'running';
ctx.totalStateChangeCount = 2;
let resumeState = 'pending';
resume.then(() => {
resumeState = 'fulfilled';
assert_equals(ctx.state, 'running', 'state on resume fulfilled.');
}).catch(() => {
// The resume() promise may be rejected if "Attempt to acquire system
// resources" fails. The spec does not discuss the possibility of a
// subsequent suspend causing such a failure, but accept this as a
// reasonable behavior.
resumeState = 'rejected';
assert_equals(ctx.state, 'suspended', 'state on resume rejected.');
assert_equals(ctx.stateChangeCount, 0);
ctx.expectedStateChangeCount = 0;
stateChangesDone = Promise.resolve();
});
suspend.then(() => {
assert_not_equals(resumeState, 'pending',
'resume promise should settle before suspend promise.')
if (resumeState == 'fulfilled') {
++ctx.expectedStateChangeCount;
}
ctx.expectedState = 'suspended';
assert_equals(ctx.state, 'suspended', 'state on suspend fulfilled.');
});
await resume;
await suspend;
await stateChangesDone;
};
// Repeat the test because Gecko uses different code when there is more than
// one AudioContext. The third run provides time to check that no further
// state changes from the second run are pending.
for (const testCount of [1, 2, 3]) {
promise_test(() => { return doTest(testCount); }, `Iteration ${testCount}`);
}
promise_test(async () => changeCountingTest.done(), 'Stop waiting');
</script>