Commit e525003f authored by Hongchan Choi's avatar Hongchan Choi Committed by Commit Bot

Do not resume a suspended BaseAudioContext when AudioWorklet starts

When AudioWorklet.addModule() activates the worklet thread, it
re-starts the destination handler even when the context is suspended.
This CL fixes the bug by restarting destination only when the context
is in the "running" state.

Bug: 950997
Test: external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-suspend.https.html
Change-Id: I0b44e3fca23bd069fac21f709fc665e8eacc4dd3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1560140
Commit-Queue: Hongchan Choi <hongchan@chromium.org>
Reviewed-by: default avatarRaymond Toy <rtoy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#649303}
parent c81a1cf3
......@@ -813,10 +813,11 @@ void BaseAudioContext::NotifyWorkletIsReady() {
audioWorklet()->GetMessagingProxy()->GetBackingWorkerThread();
}
// If the context is running or suspended, restart the destination to switch
// the render thread with the worklet thread. Note that restarting can happen
// right after the context construction.
if (ContextState() != kClosed) {
// If the context is running, restart the destination to switch the render
// thread with the worklet thread. When the context is suspended, the next
// resume() call will start rendering with the worklet thread.
// Note that restarting can happen right after the context construction.
if (ContextState() == kRunning) {
destination()->GetAudioDestinationHandler().RestartRendering();
}
}
......
......@@ -1210,6 +1210,18 @@ window.Audit = (function() {
this._taskRunner._runNextTask();
}
// Runs |subTask| |time| milliseconds later. |setTimeout| is not allowed in
// WPT linter, so a thin wrapper around the harness's |step_timeout| is
// used here.
timeout(subTask, time) {
async_test((test) => {
test.step_timeout(() => {
subTask();
test.done();
}, time);
});
}
isPassed() {
return this._state === TaskState.FINISHED && this._result;
}
......
<!DOCTYPE html>
<html>
<head>
<title>
Test if activation of worklet thread does not resume context rendering.
</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/webaudio/resources/audit.js"></script>
</head>
<body>
<script id="layout-test-code">
const audit = Audit.createTaskRunner();
const context = new AudioContext();
const filePath = 'processors/dummy-processor.js';
// Suspends the context right away and then activate worklet. The current
// time must not advance since the context is suspended.
audit.define(
{label: 'load-worklet-and-suspend'},
async (task, should) => {
context.suspend();
const suspendTime = context.currentTime;
await context.audioWorklet.addModule(filePath);
const dummy = new AudioWorkletNode(context, 'dummy');
dummy.connect(context.destination);
task.timeout(() => {
should(context.currentTime, 'context.currentTime')
.beEqualTo(suspendTime);
should(context.state, 'context.state').beEqualTo('suspended');
task.done();
}, 1000);
});
audit.run();
</script>
</body>
</html>
......@@ -1202,6 +1202,18 @@ window.Audit = (function() {
this._taskRunner._runNextTask();
}
// Runs |subTask| |time| milliseconds later. |setTimeout| is not allowed in
// WPT linter, so a thin wrapper around the harness's |step_timeout| is
// used here.
timeout(subTask, time) {
async_test((test) => {
test.step_timeout(() => {
subTask();
test.done();
}, time);
});
}
isPassed() {
return this._state === TaskState.FINISHED && this._result;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment