'use strict'; // This value is used to set the values in an AudioParam. const TestValue = 0.5; // Prepare 4 outputs; 2 outputs will be unconnected for testing. const WorkletNodeOptions = { processorOptions: {testValue: TestValue}, numberOfInputs: 0, numberOfOutputs: 4 }; // The code for the AWP definition in AudioWorkletGlobalScope. const processorCode = () => { // This processor sends the `outputs` array to the main thread at the first // process call - after filling its 2nd output with the test value. class OutputTestProcessor extends AudioWorkletProcessor { constructor(options) { super(options); this.testValue = options.processorOptions.testValue; } process(inputs, outputs) { // Fill the second output of this process with the `testValue`. const output = outputs[1]; for (const channel of output) { channel.fill(this.testValue); } // Send the outputs array and stop rendering. this.port.postMessage({outputs}); return false; } } registerProcessor('output-test-processor', OutputTestProcessor); // This process has an AudioParam and sends the `params` array to the main // thread at the first process call. class ParamTestProcessor extends AudioWorkletProcessor { static get parameterDescriptors() { return [ {name: 'testParam', defaultValue: 0.0} ]; } process(inputs, outputs, params) { // Send the params array and stop rendering. this.port.postMessage({paramValues: params.testParam}); return false; } } registerProcessor('param-test-processor', ParamTestProcessor); } const initializeAudioContext = async () => { const context = new AudioContext(); const moduleString = `(${processorCode.toString()})();`; const blobUrl = window.URL.createObjectURL( new Blob([moduleString], {type: 'text/javascript'})); await context.audioWorklet.addModule(blobUrl); context.suspend(); return context; }; // Test if unconnected outputs provides a non-zero length array for channels. promise_test(async () => { const context = await initializeAudioContext(); const outputTester = new AudioWorkletNode( context, 'output-test-processor', WorkletNodeOptions); const testGain = new GainNode(context); // Connect the 2nd output of the tester to another node. Note that // `testGain` is not connected to the destination. outputTester.connect(testGain, 1); // Connect the 4th output of the tester to the destination node. outputTester.connect(context.destination, 3); return new Promise(resolve => { outputTester.port.onmessage = resolve; context.resume(); }).then(event => { // The number of outputs should be 4, as specified above. const outputs = event.data.outputs; assert_equals(outputs.length, WorkletNodeOptions.numberOfOutputs); for (const output of outputs) { // Each output should have 1 channel of audio data per spec. assert_equals(output.length, 1); for (const channel of output) { // Each channel should have a non-zero length array. assert_true(channel.length > 0); } } context.close(); }); }, 'Test if unconnected outputs provides a non-zero length array for channels'); // Test if outputs connected to AudioParam provides a non-zero length array for // channels. promise_test(async () => { const context = await initializeAudioContext(); const outputTester = new AudioWorkletNode( context, 'output-test-processor', WorkletNodeOptions); const paramTester = new AudioWorkletNode( context, 'param-test-processor'); // Connect the 2nd output of the tester to another node's AudioParam. outputTester.connect(paramTester.parameters.get('testParam'), 1); outputTester.connect(context.destination); return new Promise(resolve => { paramTester.port.onmessage = resolve; context.resume(); }).then(event => { // The resulting values from AudioParam should be a non-zero length array // filled with `TestValue` above. const actualValues = event.data.paramValues; const expectedValues = (new Array(actualValues.length)).fill(TestValue); assert_true(actualValues.length > 0); assert_array_equals(actualValues, expectedValues); context.close(); }); }, 'Test if outputs connected to AudioParam provides a non-zero length array ' + 'for channels');