Skip to content

Commit 1330974

Browse files
hochmoz-wptsync-bot
authored andcommitted
Bug 1644847 [wpt PR 24093] - Avoid memory allocation in AudioWorkletProcessor.process(), a=testonly
Automatic update from web-platform-tests Avoid memory allocation in AudioWorkletProcessor.process() Based on the spec [1], the current implementation of AudioWorkletProcessor needs to create a new data container (i.e. WebIDL sequence<>) for input, output, and param arrays. With the new spec change [2], this CL changes the overall design of the audio processing callback: 1. Moves the processing call from AudioWorkletGlobalScope to AudioWorkletProcessor object. 2. AudioWorkletProcessor now keeps the data container within the object and allocate memory when it is needed. The preliminary benchmark shows the sizable improvement in the audio stream quality. The glitch score (= buffer underrun/total callback) is improved by ~9x in the low-tier machine. [3] This is an API change [4], but the real world impact would be negligible because there's no functionality change. [1]: https://webaudio.github.io/web-audio-api/#dom-audioworkletprocessor-process-inputs-outputs-parameters-inputs [2]: WebAudio/web-audio-api#1933 (comment) [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=1086665#c2 [4]: https://chromestatus.com/feature/5647541725036544 Bug: 1071085, 1086665 Change-Id: I3e664754973d4d86649d38c1807c6b9d7830fb96 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2218702 Reviewed-by: Raymond Toy <[email protected]> Reviewed-by: Yuki Shiino <[email protected]> Commit-Queue: Hongchan Choi <[email protected]> Cr-Commit-Position: refs/heads/master@{#779052} -- wpt-commits: 48a5574b7e1a3d7d952a4b9fe84b049375773e42 wpt-pr: 24093
1 parent b74dcce commit 1330974

File tree

2 files changed

+147
-0
lines changed

2 files changed

+147
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<title>
5+
Test given arrays within AudioWorkletProcessor.process() method
6+
</title>
7+
<script src="/resources/testharness.js"></script>
8+
<script src="/resources/testharnessreport.js"></script>
9+
<script src="/webaudio/resources/audit.js"></script>
10+
</head>
11+
12+
<body>
13+
<script>
14+
const audit = Audit.createTaskRunner();
15+
const filePath = 'processors/array-check-processor.js';
16+
const context = new AudioContext();
17+
18+
// Test if the incoming arrays are frozen as expected.
19+
audit.define('check-frozen-array', (task, should) => {
20+
context.audioWorklet.addModule(filePath).then(() => {
21+
const workletNode =
22+
new AudioWorkletNode(context, 'array-frozen-processor');
23+
workletNode.port.onmessage = (message) => {
24+
const actual = message.data;
25+
should(actual.isInputFrozen, '|inputs| is frozen').beTrue();
26+
should(actual.isOutputFrozen, '|outputs| is frozen').beTrue();
27+
task.done();
28+
};
29+
});
30+
});
31+
32+
// The incoming arrays should not be transferred, but the associated
33+
// ArrayBuffers can be transferred. See the `array-transfer-processor`
34+
// definition for the details.
35+
audit.define('transfer-frozen-array', (task, should) => {
36+
const sourceNode = new ConstantSourceNode(context);
37+
const workletNode =
38+
new AudioWorkletNode(context, 'array-transfer-processor');
39+
workletNode.port.onmessage = (message) => {
40+
const actual = message.data;
41+
if (actual.type === 'assertion')
42+
should(actual.success, actual.message).beTrue();
43+
if (actual.done)
44+
task.done();
45+
};
46+
sourceNode.connect(workletNode);
47+
sourceNode.start();
48+
});
49+
50+
audit.run();
51+
</script>
52+
</body>
53+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**
2+
* @class ArrayFrozenProcessor
3+
* @extends AudioWorkletProcessor
4+
*/
5+
class ArrayFrozenProcessor extends AudioWorkletProcessor {
6+
constructor() {
7+
super();
8+
this._messageSent = false;
9+
}
10+
11+
process(inputs, outputs, parameters) {
12+
const input = inputs[0];
13+
const output = outputs[0];
14+
15+
if (!this._messageSent) {
16+
this.port.postMessage({
17+
inputLength: input.length,
18+
isInputFrozen: Object.isFrozen(inputs) && Object.isFrozen(input),
19+
outputLength: output.length,
20+
isOutputFrozen: Object.isFrozen(outputs) && Object.isFrozen(output)
21+
});
22+
this._messageSent = true;
23+
}
24+
25+
return false;
26+
}
27+
}
28+
29+
/**
30+
* @class ArrayTransferProcessor
31+
* @extends AudioWorkletProcessor
32+
*/
33+
class ArrayTransferProcessor extends AudioWorkletProcessor {
34+
constructor() {
35+
super();
36+
this._messageSent = false;
37+
}
38+
39+
process(inputs, outputs, parameters) {
40+
const input = inputs[0];
41+
const output = outputs[0];
42+
43+
if (!this._messageSent) {
44+
try {
45+
// Transferring Array objects should NOT work.
46+
this.port.postMessage({
47+
inputs, input, inputChannel: input[0],
48+
outputs, output, outputChannel: output[0]
49+
}, [inputs, input, inputs[0], outputs, output, output[0]]);
50+
// Hence, the following must NOT be reached.
51+
this.port.postMessage({
52+
type: 'assertion',
53+
success: false,
54+
message: 'Transferring inputs/outputs, an individual input/output ' +
55+
'array, or a channel Float32Array MUST fail, but succeeded.'
56+
});
57+
} catch (error) {
58+
this.port.postMessage({
59+
type: 'assertion',
60+
success: true,
61+
message: 'Transferring inputs/outputs, an individual input/output ' +
62+
'array, or a channel Float32Array is not allowed as expected.'
63+
});
64+
}
65+
66+
try {
67+
// Transferring ArrayBuffers should work.
68+
this.port.postMessage(
69+
{inputChannel: input[0], outputChannel: output[0]},
70+
[input[0].buffer, output[0].buffer]);
71+
this.port.postMessage({
72+
type: 'assertion',
73+
success: true,
74+
message: 'Transferring ArrayBuffers was successful as expected.'
75+
});
76+
} catch (error) {
77+
// This must NOT be reached.
78+
this.port.postMessage({
79+
type: 'assertion',
80+
success: false,
81+
message: 'Transferring ArrayBuffers unexpectedly failed.'
82+
});
83+
}
84+
85+
this.port.postMessage({done: true});
86+
this._messageSent = true;
87+
}
88+
89+
return false;
90+
}
91+
}
92+
93+
registerProcessor('array-frozen-processor', ArrayFrozenProcessor);
94+
registerProcessor('array-transfer-processor', ArrayTransferProcessor);

0 commit comments

Comments
 (0)