-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <rtoy@chromium.org> Reviewed-by: Yuki Shiino <yukishiino@chromium.org> Commit-Queue: Hongchan Choi <hongchan@chromium.org> Cr-Commit-Position: refs/heads/master@{#779052}
- Loading branch information
1 parent
604b851
commit 610d212
Showing
2 changed files
with
147 additions
and
0 deletions.
There are no files selected for viewing
53 changes: 53 additions & 0 deletions
53
...udio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<title> | ||
Test given arrays within AudioWorkletProcessor.process() method | ||
</title> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="/webaudio/resources/audit.js"></script> | ||
</head> | ||
|
||
<body> | ||
<script> | ||
const audit = Audit.createTaskRunner(); | ||
const filePath = 'processors/array-check-processor.js'; | ||
const context = new AudioContext(); | ||
|
||
// Test if the incoming arrays are frozen as expected. | ||
audit.define('check-frozen-array', (task, should) => { | ||
context.audioWorklet.addModule(filePath).then(() => { | ||
const workletNode = | ||
new AudioWorkletNode(context, 'array-frozen-processor'); | ||
workletNode.port.onmessage = (message) => { | ||
const actual = message.data; | ||
should(actual.isInputFrozen, '|inputs| is frozen').beTrue(); | ||
should(actual.isOutputFrozen, '|outputs| is frozen').beTrue(); | ||
task.done(); | ||
}; | ||
}); | ||
}); | ||
|
||
// The incoming arrays should not be transferred, but the associated | ||
// ArrayBuffers can be transferred. See the `array-transfer-processor` | ||
// definition for the details. | ||
audit.define('transfer-frozen-array', (task, should) => { | ||
const sourceNode = new ConstantSourceNode(context); | ||
const workletNode = | ||
new AudioWorkletNode(context, 'array-transfer-processor'); | ||
workletNode.port.onmessage = (message) => { | ||
const actual = message.data; | ||
if (actual.type === 'assertion') | ||
should(actual.success, actual.message).beTrue(); | ||
if (actual.done) | ||
task.done(); | ||
}; | ||
sourceNode.connect(workletNode); | ||
sourceNode.start(); | ||
}); | ||
|
||
audit.run(); | ||
</script> | ||
</body> | ||
</html> |
94 changes: 94 additions & 0 deletions
94
webaudio/the-audio-api/the-audioworklet-interface/processors/array-check-processor.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/** | ||
* @class ArrayFrozenProcessor | ||
* @extends AudioWorkletProcessor | ||
*/ | ||
class ArrayFrozenProcessor extends AudioWorkletProcessor { | ||
constructor() { | ||
super(); | ||
this._messageSent = false; | ||
} | ||
|
||
process(inputs, outputs, parameters) { | ||
const input = inputs[0]; | ||
const output = outputs[0]; | ||
|
||
if (!this._messageSent) { | ||
this.port.postMessage({ | ||
inputLength: input.length, | ||
isInputFrozen: Object.isFrozen(inputs) && Object.isFrozen(input), | ||
outputLength: output.length, | ||
isOutputFrozen: Object.isFrozen(outputs) && Object.isFrozen(output) | ||
}); | ||
this._messageSent = true; | ||
} | ||
|
||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* @class ArrayTransferProcessor | ||
* @extends AudioWorkletProcessor | ||
*/ | ||
class ArrayTransferProcessor extends AudioWorkletProcessor { | ||
constructor() { | ||
super(); | ||
this._messageSent = false; | ||
} | ||
|
||
process(inputs, outputs, parameters) { | ||
const input = inputs[0]; | ||
const output = outputs[0]; | ||
|
||
if (!this._messageSent) { | ||
try { | ||
// Transferring Array objects should NOT work. | ||
this.port.postMessage({ | ||
inputs, input, inputChannel: input[0], | ||
outputs, output, outputChannel: output[0] | ||
}, [inputs, input, inputs[0], outputs, output, output[0]]); | ||
// Hence, the following must NOT be reached. | ||
this.port.postMessage({ | ||
type: 'assertion', | ||
success: false, | ||
message: 'Transferring inputs/outputs, an individual input/output ' + | ||
'array, or a channel Float32Array MUST fail, but succeeded.' | ||
}); | ||
} catch (error) { | ||
this.port.postMessage({ | ||
type: 'assertion', | ||
success: true, | ||
message: 'Transferring inputs/outputs, an individual input/output ' + | ||
'array, or a channel Float32Array is not allowed as expected.' | ||
}); | ||
} | ||
|
||
try { | ||
// Transferring ArrayBuffers should work. | ||
this.port.postMessage( | ||
{inputChannel: input[0], outputChannel: output[0]}, | ||
[input[0].buffer, output[0].buffer]); | ||
this.port.postMessage({ | ||
type: 'assertion', | ||
success: true, | ||
message: 'Transferring ArrayBuffers was successful as expected.' | ||
}); | ||
} catch (error) { | ||
// This must NOT be reached. | ||
this.port.postMessage({ | ||
type: 'assertion', | ||
success: false, | ||
message: 'Transferring ArrayBuffers unexpectedly failed.' | ||
}); | ||
} | ||
|
||
this.port.postMessage({done: true}); | ||
this._messageSent = true; | ||
} | ||
|
||
return false; | ||
} | ||
} | ||
|
||
registerProcessor('array-frozen-processor', ArrayFrozenProcessor); | ||
registerProcessor('array-transfer-processor', ArrayTransferProcessor); |