diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors')
30 files changed, 1010 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/active-processing.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/active-processing.js new file mode 100644 index 0000000000..ef497733ca --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/active-processing.js @@ -0,0 +1,54 @@ +/** + * @class ActiveProcessingTester + * @extends AudioWorkletProcessor + * + * This processor class sends a message to its AudioWorkletNodew whenever the + * number of channels on the input changes. The message includes the actual + * number of channels, the context time at which this occurred, and whether + * we're done processing or not. + */ +class ActiveProcessingTester extends AudioWorkletProcessor { + constructor(options) { + super(options); + this._lastChannelCount = 0; + + // See if user specified a value for test duration. + if (options.hasOwnProperty('processorOptions') && + options.processorOptions.hasOwnProperty('testDuration')) { + this._testDuration = options.processorOptions.testDuration; + } else { + this._testDuration = 5; + } + + // Time at which we'll signal we're done, based on the requested + // |testDuration| + this._endTime = currentTime + this._testDuration; + } + + process(inputs, outputs) { + const input = inputs[0]; + const output = outputs[0]; + const inputChannelCount = input.length; + const isFinished = currentTime > this._endTime; + + // Send a message if we're done or the count changed. + if (isFinished || (inputChannelCount != this._lastChannelCount)) { + this.port.postMessage({ + channelCount: inputChannelCount, + finished: isFinished, + time: currentTime + }); + this._lastChannelCount = inputChannelCount; + } + + // Just copy the input to the output for no particular reason. + for (let channel = 0; channel < input.length; ++channel) { + output[channel].set(input[channel]); + } + + // When we're finished, this method no longer needs to be called. + return !isFinished; + } +} + +registerProcessor('active-processing-tester', ActiveProcessingTester); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/add-offset.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/add-offset.js new file mode 100644 index 0000000000..d05056bd84 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/add-offset.js @@ -0,0 +1,34 @@ +/* + * @class AddOffsetProcessor + * @extends AudioWorkletProcessor + * + * Just adds a fixed value to the input + */ +class AddOffsetProcessor extends AudioWorkletProcessor { + constructor(options) { + super(); + + this._offset = options.processorOptions.offset; + } + + process(inputs, outputs) { + // This processor assumes the node has at least 1 input and 1 output. + let input = inputs[0]; + let output = outputs[0]; + let outputChannel = output[0]; + + if (input.length > 0) { + let inputChannel = input[0]; + for (let k = 0; k < outputChannel.length; ++k) + outputChannel[k] = inputChannel[k] + this._offset; + } else { + // No input connected, so pretend it's silence and just fill the + // output with the offset value. + outputChannel.fill(this._offset); + } + + return true; + } +} + +registerProcessor('add-offset-processor', AddOffsetProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/array-check-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/array-check-processor.js new file mode 100644 index 0000000000..d6eeff3d15 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/array-check-processor.js @@ -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); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/channel-count-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/channel-count-processor.js new file mode 100644 index 0000000000..556459f46b --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/channel-count-processor.js @@ -0,0 +1,19 @@ +/** + * @class ChannelCountProcessor + * @extends AudioWorkletProcessor + */ +class ChannelCountProcessor extends AudioWorkletProcessor { + constructor(options) { + super(options); + } + + process(inputs, outputs) { + this.port.postMessage({ + inputChannel: inputs[0].length, + outputChannel: outputs[0].length + }); + return false; + } +} + +registerProcessor('channel-count', ChannelCountProcessor);
\ No newline at end of file diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-new-after-new.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-new-after-new.js new file mode 100644 index 0000000000..d4c63f7775 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-new-after-new.js @@ -0,0 +1,16 @@ +class NewAfterNew extends AudioWorkletProcessor { + constructor() { + const processor = new AudioWorkletProcessor() + let message = {threw: false}; + try { + new AudioWorkletProcessor(); + } catch (e) { + message.threw = true; + message.errorName = e.name; + message.isTypeError = e instanceof TypeError; + } + processor.port.postMessage(message); + return processor; + } +} +registerProcessor("new-after-new", NewAfterNew); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-new-after-super.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-new-after-super.js new file mode 100644 index 0000000000..a6d4f0e2e8 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-new-after-super.js @@ -0,0 +1,15 @@ +class NewAfterSuper extends AudioWorkletProcessor { + constructor() { + super() + let message = {threw: false}; + try { + new AudioWorkletProcessor() + } catch (e) { + message.threw = true; + message.errorName = e.name; + message.isTypeError = e instanceof TypeError; + } + this.port.postMessage(message); + } +} +registerProcessor("new-after-super", NewAfterSuper); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-singleton.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-singleton.js new file mode 100644 index 0000000000..c40b5a7179 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-singleton.js @@ -0,0 +1,16 @@ +let singleton; +class Singleton extends AudioWorkletProcessor { + constructor() { + if (!singleton) { + singleton = new AudioWorkletProcessor(); + singleton.process = function() { + this.port.postMessage({message: "process called"}); + // This function will be called at most once for each AudioWorkletNode + // if the node has no input connections. + return false; + } + } + return singleton; + } +} +registerProcessor("singleton", Singleton); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-super-after-new.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-super-after-new.js new file mode 100644 index 0000000000..e447830c5f --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/construction-port-super-after-new.js @@ -0,0 +1,16 @@ +class SuperAfterNew extends AudioWorkletProcessor { + constructor() { + const processor = new AudioWorkletProcessor() + let message = {threw: false}; + try { + super(); + } catch (e) { + message.threw = true; + message.errorName = e.name; + message.isTypeError = e instanceof TypeError; + } + processor.port.postMessage(message); + return processor; + } +} +registerProcessor("super-after-new", SuperAfterNew); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/denormal-test-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/denormal-test-processor.js new file mode 100644 index 0000000000..2b7929437d --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/denormal-test-processor.js @@ -0,0 +1,12 @@ +class DenormalTestProcessor extends AudioWorkletProcessor { + process() { + // The denormals should be non-zeros. Otherwise, it's a violation of + // ECMA specification: https://tc39.es/ecma262/#sec-number.min_value + this.port.postMessage({ + result: Number.MIN_VALUE !== 0.0 + }); + return false; + } +} + +registerProcessor('denormal-test', DenormalTestProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dummy-processor-globalthis.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dummy-processor-globalthis.js new file mode 100644 index 0000000000..d1b16cc9aa --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dummy-processor-globalthis.js @@ -0,0 +1,12 @@ +class DummyProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process(inputs, outputs, parameters) { + // Doesn't do anything here. + return true; + } +} + +globalThis.registerProcessor('dummy-globalthis', DummyProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dummy-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dummy-processor.js new file mode 100644 index 0000000000..11155d508c --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dummy-processor.js @@ -0,0 +1,18 @@ +/** + * @class DummyProcessor + * @extends AudioWorkletProcessor + * + * This processor class demonstrates the bare-bone structure of the processor. + */ +class DummyProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process(inputs, outputs, parameters) { + // Doesn't do anything here. + return true; + } +} + +registerProcessor('dummy', DummyProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dynamic-register-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dynamic-register-processor.js new file mode 100644 index 0000000000..5e825aebb4 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/dynamic-register-processor.js @@ -0,0 +1,22 @@ +class ProcessorA extends AudioWorkletProcessor { + process() { + return true; + } +} + +// ProcessorB registers ProcessorA upon the construction. +class ProcessorB extends AudioWorkletProcessor { + constructor() { + super(); + this.port.onmessage = () => { + registerProcessor('ProcessorA', ProcessorA); + this.port.postMessage({}); + }; + } + + process() { + return true; + } +} + +registerProcessor('ProcessorB', ProcessorB); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/error-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/error-processor.js new file mode 100644 index 0000000000..66ff5e2e25 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/error-processor.js @@ -0,0 +1,40 @@ +/** + * @class ConstructorErrorProcessor + * @extends AudioWorkletProcessor + */ +class ConstructorErrorProcessor extends AudioWorkletProcessor { + constructor() { + throw 'ConstructorErrorProcessor: an error thrown from constructor.'; + } + + process() { + return true; + } +} + + +/** + * @class ProcessErrorProcessor + * @extends AudioWorkletProcessor + */ +class ProcessErrorProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process() { + throw 'ProcessErrorProcessor: an error throw from process method.'; + return true; + } +} + + +/** + * @class EmptyErrorProcessor + * @extends AudioWorkletProcessor + */ +class EmptyErrorProcessor extends AudioWorkletProcessor { process() {} } + +registerProcessor('constructor-error', ConstructorErrorProcessor); +registerProcessor('process-error', ProcessErrorProcessor); +registerProcessor('empty-error', EmptyErrorProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/gain-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/gain-processor.js new file mode 100644 index 0000000000..e9e130e374 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/gain-processor.js @@ -0,0 +1,38 @@ +/** + * @class GainProcessor + * @extends AudioWorkletProcessor + * + * This processor class demonstrates the bare-bone structure of the processor. + */ +class GainProcessor extends AudioWorkletProcessor { + static get parameterDescriptors() { + return [ + {name: 'gain', defaultValue: 0.707} + ]; + } + + constructor() { + super(); + } + + process(inputs, outputs, parameters) { + let input = inputs[0]; + let output = outputs[0]; + let gain = parameters.gain; + for (let channel = 0; channel < input.length; ++channel) { + let inputChannel = input[channel]; + let outputChannel = output[channel]; + if (gain.length === 1) { + for (let i = 0; i < inputChannel.length; ++i) + outputChannel[i] = inputChannel[i] * gain[0]; + } else { + for (let i = 0; i < inputChannel.length; ++i) + outputChannel[i] = inputChannel[i] * gain[i]; + } + } + + return true; + } +} + +registerProcessor('gain', GainProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/input-count-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/input-count-processor.js new file mode 100644 index 0000000000..6d53ba84c7 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/input-count-processor.js @@ -0,0 +1,22 @@ +/** + * @class CountProcessor + * @extends AudioWorkletProcessor + * + * This processor class just looks at the number of input channels on the first + * input and fills the first output channel with that value. + */ +class CountProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process(inputs, outputs, parameters) { + let input = inputs[0]; + let output = outputs[0]; + output[0].fill(input.length); + + return true; + } +} + +registerProcessor('counter', CountProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/input-length-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/input-length-processor.js new file mode 100644 index 0000000000..be485f03e8 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/input-length-processor.js @@ -0,0 +1,27 @@ +/** + * @class InputLengthProcessor + * @extends AudioWorkletProcessor + * + * This processor class just sets the output to the length of the + * input array for verifying that the input length changes when the + * input is disconnected. + */ +class InputLengthProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + process(inputs, outputs, parameters) { + let input = inputs[0]; + let output = outputs[0]; + + // Set output channel to the length of the input channel array. + // If the input is unconnected, set the value to zero. + const fillValue = input.length > 0 ? input[0].length : 0; + output[0].fill(fillValue); + + return true; + } +} + +registerProcessor('input-length-processor', InputLengthProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/invalid-param-array-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/invalid-param-array-processor.js new file mode 100644 index 0000000000..e4a5dc39ba --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/invalid-param-array-processor.js @@ -0,0 +1,47 @@ +/** + * @class InvalidParamArrayProcessor + * @extends AudioWorkletProcessor + * + * This processor intentionally returns an array with an invalid size when the + * processor's getter is queried. + */ +let singleton = undefined; +let secondFetch = false; +let useDescriptor = false; +let processCounter = 0; + +class InvalidParamArrayProcessor extends AudioWorkletProcessor { + static get parameterDescriptors() { + if (useDescriptor) + return [{name: 'invalidParam'}]; + useDescriptor = true; + return []; + } + + constructor() { + super(); + if (singleton === undefined) + singleton = this; + return singleton; + } + + process(inputs, outputs, parameters) { + const output = outputs[0]; + for (let channel = 0; channel < output.length; ++channel) + output[channel].fill(1); + return false; + } +} + +// This overridden getter is invoked under the hood before process() gets +// called. After this gets called, process() method above will be invalidated, +// and mark the worklet node non-functional. (i.e. in an error state) +Object.defineProperty(Object.prototype, 'invalidParam', {'get': () => { + if (secondFetch) + return new Float32Array(256); + secondFetch = true; + return new Float32Array(128); +}}); + +registerProcessor('invalid-param-array-1', InvalidParamArrayProcessor); +registerProcessor('invalid-param-array-2', InvalidParamArrayProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/one-pole-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/one-pole-processor.js new file mode 100644 index 0000000000..0bcc43f6f0 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/one-pole-processor.js @@ -0,0 +1,49 @@ +/** + * @class OnePoleFilter + * @extends AudioWorkletProcessor + * + * A simple One-pole filter. + */ + +class OnePoleFilter extends AudioWorkletProcessor { + + // This gets evaluated as soon as the global scope is created. + static get parameterDescriptors() { + return [{ + name: 'frequency', + defaultValue: 250, + minValue: 0, + maxValue: 0.5 * sampleRate + }]; + } + + constructor() { + super(); + this.updateCoefficientsWithFrequency_(250); + } + + updateCoefficientsWithFrequency_(frequency) { + this.b1_ = Math.exp(-2 * Math.PI * frequency / sampleRate); + this.a0_ = 1.0 - this.b1_; + this.z1_ = 0; + } + + process(inputs, outputs, parameters) { + let input = inputs[0]; + let output = outputs[0]; + let frequency = parameters.frequency; + for (let channel = 0; channel < output.length; ++channel) { + let inputChannel = input[channel]; + let outputChannel = output[channel]; + for (let i = 0; i < outputChannel.length; ++i) { + this.updateCoefficientsWithFrequency_(frequency[i]); + this.z1_ = inputChannel[i] * this.a0_ + this.z1_ * this.b1_; + outputChannel[i] = this.z1_; + } + } + + return true; + } +} + +registerProcessor('one-pole-filter', OnePoleFilter); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/option-test-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/option-test-processor.js new file mode 100644 index 0000000000..27e1da6325 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/option-test-processor.js @@ -0,0 +1,19 @@ +/** + * @class OptionTestProcessor + * @extends AudioWorkletProcessor + * + * This processor class demonstrates the option passing feature by echoing the + * received |nodeOptions| back to the node. + */ +class OptionTestProcessor extends AudioWorkletProcessor { + constructor(nodeOptions) { + super(); + this.port.postMessage(nodeOptions); + } + + process() { + return true; + } +} + +registerProcessor('option-test-processor', OptionTestProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/param-size-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/param-size-processor.js new file mode 100644 index 0000000000..d7ce836500 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/param-size-processor.js @@ -0,0 +1,30 @@ +/** + * @class ParamSizeProcessor + * @extends AudioWorkletProcessor + * + * This processor is a source node which basically outputs the size of the + * AudioParam array for each render quantum. + */ + +class ParamSizeProcessor extends AudioWorkletProcessor { + static get parameterDescriptors() { + return [{name: 'param'}]; + } + + constructor() { + super(); + } + + process(inputs, outputs, parameters) { + let output = outputs[0]; + let param = parameters.param; + + for (let channel = 0; channel < output.length; ++channel) { + output[channel].fill(param.length); + } + + return true; + } +} + +registerProcessor('param-size', ParamSizeProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/port-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/port-processor.js new file mode 100644 index 0000000000..8def5a61d7 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/port-processor.js @@ -0,0 +1,34 @@ +/** + * @class PortProcessor + * @extends AudioWorkletProcessor + * + * This processor class demonstrates the message port functionality. + */ +class PortProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.port.onmessage = this.handleMessage.bind(this); + this.port.postMessage({ + state: 'created', + timeStamp: currentTime, + currentFrame: currentFrame + }); + this.processCallCount = 0; + } + + handleMessage(event) { + this.port.postMessage({ + message: event.data, + timeStamp: currentTime, + currentFrame: currentFrame, + processCallCount: this.processCallCount + }); + } + + process() { + ++this.processCallCount; + return true; + } +} + +registerProcessor('port-processor', PortProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-getter-test-instance-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-getter-test-instance-processor.js new file mode 100644 index 0000000000..b1434f54ba --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-getter-test-instance-processor.js @@ -0,0 +1,44 @@ +/** + * @class ProcessGetterTestInstanceProcessor + * @extends AudioWorkletProcessor + * + * This processor class tests that a 'process' getter on an + * AudioWorkletProcessorConstructor instance is called at the right times. + */ + +class ProcessGetterTestInstanceProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.getterCallCount = 0; + this.totalProcessCallCount = 0; + Object.defineProperty(this, 'process', { get: function() { + if (!(this instanceof ProcessGetterTestInstanceProcessor)) { + throw new Error('`process` getter called with bad `this`.'); + } + ++this.getterCallCount; + let functionCallCount = 0; + return () => { + if (++functionCallCount > 1) { + const message = 'Closure of function returned from `process` getter' + + ' should be used for only one call.' + this.port.postMessage({message: message}); + throw new Error(message); + } + if (++this.totalProcessCallCount < 2) { + return true; // Expect another getter call. + } + if (this.totalProcessCallCount != this.getterCallCount) { + const message = + 'Getter should be called only once for each process() call.' + this.port.postMessage({message: message}); + throw new Error(message); + } + this.port.postMessage({message: 'done'}); + return false; // No more calls required. + }; + }}); + } +} + +registerProcessor('process-getter-test-instance', + ProcessGetterTestInstanceProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-getter-test-prototype-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-getter-test-prototype-processor.js new file mode 100644 index 0000000000..cef5fa8b52 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-getter-test-prototype-processor.js @@ -0,0 +1,55 @@ +/** + * @class ProcessGetterTestPrototypeProcessor + * @extends AudioWorkletProcessor + * + * This processor class tests that a 'process' getter on + * AudioWorkletProcessorConstructor is called at the right times. + */ + +// Reporting errors during registerProcess() is awkward. +// The occurrance of an error is flagged, so that a trial registration can be +// performed and registration against the expected AudioWorkletNode name is +// performed only if no errors are flagged during the trial registration. +let error_flag = false; + +class ProcessGetterTestPrototypeProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.getterCallCount = 0; + this.totalProcessCallCount = 0; + } + get process() { + if (!(this instanceof ProcessGetterTestPrototypeProcessor)) { + error_flag = true; + throw new Error('`process` getter called with bad `this`.'); + } + ++this.getterCallCount; + let functionCallCount = 0; + return () => { + if (++functionCallCount > 1) { + const message = 'Closure of function returned from `process` getter' + + ' should be used for only one call.' + this.port.postMessage({message: message}); + throw new Error(message); + } + if (++this.totalProcessCallCount < 2) { + return true; // Expect another getter call. + } + if (this.totalProcessCallCount != this.getterCallCount) { + const message = + 'Getter should be called only once for each process() call.' + this.port.postMessage({message: message}); + throw new Error(message); + } + this.port.postMessage({message: 'done'}); + return false; // No more calls required. + }; + } +} + +registerProcessor('trial-process-getter-test-prototype', + ProcessGetterTestPrototypeProcessor); +if (!error_flag) { + registerProcessor('process-getter-test-prototype', + ProcessGetterTestPrototypeProcessor); +} diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-parameter-test-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-parameter-test-processor.js new file mode 100644 index 0000000000..a300d3cdec --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/process-parameter-test-processor.js @@ -0,0 +1,18 @@ +/** + * @class ProcessParameterTestProcessor + * @extends AudioWorkletProcessor + * + * This processor class forwards input and output parameters to its + * AudioWorkletNode. + */ +class ProcessParameterTestProcessor extends AudioWorkletProcessor { + process(inputs, outputs) { + this.port.postMessage({ + inputs: inputs, + outputs: outputs + }); + return false; + } +} + +registerProcessor('process-parameter-test', ProcessParameterTestProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/promise-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/promise-processor.js new file mode 100644 index 0000000000..6a8144b3cc --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/promise-processor.js @@ -0,0 +1,40 @@ +/** + * @class PromiseProcessor + * @extends AudioWorkletProcessor + * + * This processor creates and resolves a promise in its `process` method. When + * the handler passed to `then()` is called, a counter that is global in the + * global scope is incremented. There are two copies of this + * AudioWorkletNode/Processor, so the counter should always be even in the + * process method of the AudioWorklet processing, since the Promise completion + * handler are resolved in between render quanta. + * + * After a few iterations of the test, one of the worklet posts back the string + * "ok" to the main thread, and the test is considered a success. + */ +var idx = 0; + +class PromiseProcessor extends AudioWorkletProcessor { + constructor(options) { + super(options); + } + + process(inputs, outputs) { + if (idx % 2 != 0) { + this.port.postMessage("ko"); + // Don't bother continuing calling process in this case, the test has + // already failed. + return false; + } + Promise.resolve().then(() => { + idx++; + if (idx == 100) { + this.port.postMessage("ok"); + } + }); + // Ensure process is called again. + return true; + } +} + +registerProcessor('promise-processor', PromiseProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/register-processor-typeerrors.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/register-processor-typeerrors.js new file mode 100644 index 0000000000..93894842fc --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/register-processor-typeerrors.js @@ -0,0 +1,39 @@ +// For cross-thread messaging. +class MessengerProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.port.onmessage = this.startTest.bind(this); + } + + process() {} + + startTest(message) { + runRegisterProcessorTest(this.port); + } +} + +function runRegisterProcessorTest(messagePort) { + try { + // TypeError when a given parameter is not a Function. + const DummyObject = {}; + registerProcessor('type-error-on-object', DummyObject); + } catch (exception) { + messagePort.postMessage({ + name: exception.name, + message: exception.message + }); + } + + try { + // TypeError When a given parameter is a Function, but not a constructor. + const DummyFunction = () => {}; + registerProcessor('type-error-on-function', DummyFunction); + } catch (exception) { + messagePort.postMessage({ + name: exception.name, + message: exception.message + }); + } +} + +registerProcessor('messenger-processor', MessengerProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/sharedarraybuffer-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/sharedarraybuffer-processor.js new file mode 100644 index 0000000000..2ccacccd4b --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/sharedarraybuffer-processor.js @@ -0,0 +1,35 @@ +/** + * @class SharedArrayBufferProcessor + * @extends AudioWorkletProcessor + * + * This processor class demonstrates passing SharedArrayBuffers to and from + * workers. + */ +class SharedArrayBufferProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.port.onmessage = this.handleMessage.bind(this); + this.port.onmessageerror = this.handleMessageError.bind(this); + let sab = new SharedArrayBuffer(8); + this.port.postMessage({state: 'created', sab}); + } + + handleMessage(event) { + this.port.postMessage({ + state: 'received message', + isSab: event.data instanceof SharedArrayBuffer + }); + } + + handleMessageError(event) { + this.port.postMessage({ + state: 'received messageerror' + }); + } + + process() { + return true; + } +} + +registerProcessor('sharedarraybuffer-processor', SharedArrayBufferProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/timing-info-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/timing-info-processor.js new file mode 100644 index 0000000000..714e32dbb5 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/timing-info-processor.js @@ -0,0 +1,25 @@ +/** + * @class TimingInfoProcessor + * @extends AudioWorkletProcessor + * + * This processor class is to test the timing information in AWGS. + */ +class TimingInfoProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.port.onmessage = this.echoMessage.bind(this); + } + + echoMessage(event) { + this.port.postMessage({ + currentTime: currentTime, + currentFrame: currentFrame + }); + } + + process() { + return true; + } +} + +registerProcessor('timing-info-processor', TimingInfoProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/zero-output-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/zero-output-processor.js new file mode 100644 index 0000000000..2d7399ca3b --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/zero-output-processor.js @@ -0,0 +1,42 @@ +/** + * @class ZeroOutputProcessor + * @extends AudioWorkletProcessor + * + * This processor accumulates the incoming buffer and send the buffered data + * to the main thread when it reaches the specified frame length. The processor + * only supports the single input. + */ + +const kRenderQuantumFrames = 128; + +class ZeroOutputProcessor extends AudioWorkletProcessor { + constructor(options) { + super(); + + this._framesRequested = options.processorOptions.bufferLength; + this._framesCaptured = 0; + this._buffer = []; + for (let i = 0; i < options.processorOptions.channeCount; ++i) { + this._buffer[i] = new Float32Array(this._framesRequested); + } + } + + process(inputs) { + let input = inputs[0]; + let startIndex = this._framesCaptured; + let endIndex = startIndex + kRenderQuantumFrames; + for (let i = 0; i < this._buffer.length; ++i) { + this._buffer[i].subarray(startIndex, endIndex).set(input[i]); + } + this._framesCaptured = endIndex; + + if (this._framesCaptured >= this._framesRequested) { + this.port.postMessage({ capturedBuffer: this._buffer }); + return false; + } else { + return true; + } + } +} + +registerProcessor('zero-output-processor', ZeroOutputProcessor); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/zero-outputs-check-processor.js b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/zero-outputs-check-processor.js new file mode 100644 index 0000000000..f816e918a2 --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioworklet-interface/processors/zero-outputs-check-processor.js @@ -0,0 +1,78 @@ +/** + * Returns true if a given AudioPort is completely filled with zero samples. + * "AudioPort" is a short-hand for FrozenArray<FrozenArray<Float32Array>>. + * + * @param {FrozenArray<FrozenArray<Float32Array>>} audioPort + * @returns bool + */ +function IsAllZero(audioPort) { + for (let busIndex = 0; busIndex < audioPort.length; ++busIndex) { + const audioBus = audioPort[busIndex]; + for (let channelIndex = 0; channelIndex < audioBus.length; ++channelIndex) { + const audioChannel = audioBus[channelIndex]; + for (let sample = 0; sample < audioChannel.length; ++sample) { + if (audioChannel[sample] != 0) + return false; + } + } + } + return true; +} + +const kRenderQuantumFrames = 128; +const kTestLengthInSec = 1.0; +const kPulseDuration = 100; + +/** + * Checks the |outputs| argument of AudioWorkletProcessor.process() and + * send a message to an associated AudioWorkletNode. It needs to be all zero + * at all times. + * + * @class ZeroOutputsCheckProcessor + * @extends {AudioWorkletProcessor} + */ +class ZeroOutputsCheckProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.startTime = currentTime; + this.counter = 0; + } + + process(inputs, outputs) { + if (!IsAllZero(outputs)) { + this.port.postMessage({ + type: 'assertion', + success: false, + message: 'Unexpected Non-zero sample found in |outputs|.' + }); + return false; + } + + if (currentTime - this.startTime >= kTestLengthInSec) { + this.port.postMessage({ + type: 'assertion', + success: true, + message: `|outputs| has been all zeros for ${kTestLengthInSec} ` + + 'seconds as expected.' + }); + return false; + } + + // Every ~0.25 second (100 render quanta), switch between outputting white + // noise and just exiting without doing anything. (from crbug.com/1099756) + this.counter++; + if (Math.floor(this.counter / kPulseDuration) % 2 == 0) + return true; + + let output = outputs[0]; + for (let channel = 0; channel < output.length; ++channel) { + for (let sample = 0; sample < 128; sample++) { + output[channel][sample] = 0.1 * (Math.random() - 0.5); + } + } + + return true; + } +} + +registerProcessor('zero-outputs-check-processor', ZeroOutputsCheckProcessor); |