blob: c1c517407abc2e459cbf1a22b98b1f5836b60abe [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<title>
Test AudioWorkletProcessorState in AudioWorkletNode
</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../../../webaudio-resources/audit.js"></script>
<script src="audio-worklet-common.js"></script>
</head>
<body>
<script id="layout-test-code">
// TODO(hongchan): remove this assertion when AudioWorklet shipped.
assertAudioWorklet();
let audit = Audit.createTaskRunner();
const sampleRate = 48000;
const renderLength = sampleRate * 0.1;
// Test "pending", "running" and "stopped" state transition.
audit.define('pending-running-stopped',
(task, should) => {
let context = new OfflineAudioContext(1, renderLength, sampleRate);
context.audioWorklet.addModule('state-processor.js').then(() => {
let timedWorkletNode = new AudioWorkletNode(context, 'timed');
// The construction of associated processor has not been
// completed. In this state, no audio processing can happen and
// all messages to the processor will be queued.
should(timedWorkletNode.processorState,
'Checking the processor state upon the constructor call')
.beEqualTo('pending');
timedWorkletNode.connect(context.destination);
// Checks the handler of |onprocessorstatechange|. Because the
// processor script is correct, the |running| state change MUST
// be fired.
let isFirstPhase = true;
timedWorkletNode.onprocessorstatechange = () => {
// The first phase should be "running".
if (isFirstPhase) {
should(timedWorkletNode.processorState,
'Checking the processor state upon ' +
'processorstatechange event')
.beEqualTo('running');
isFirstPhase = false;
} else {
// The second phase in this test must be "stopped".
should(timedWorkletNode.processorState,
'Checking the processor state after ' +
'processor stopped processing')
.beEqualTo('stopped');
task.done();
}
};
context.startRendering();
});
});
// Test the error state caused by the failure of processor constructor.
audit.define('constructor-error',
(task, should) => {
let context = new OfflineAudioContext(1, renderLength, sampleRate);
context.audioWorklet.addModule('state-processor.js').then(() => {
let constructorErrorWorkletNode =
new AudioWorkletNode(context, 'constructor-error');
should(constructorErrorWorkletNode.processorState,
'constructorErrorWorkletNode.processorState after ' +
'its construction')
.beEqualTo('pending');
constructorErrorWorkletNode.onprocessorstatechange = () => {
should(constructorErrorWorkletNode.processorState,
'workletNode.processorState upon processorstatechange ' +
'event after the failure from processor.constructor()')
.beEqualTo('error');
task.done();
};
});
});
// Test the error state caused by the failure of processor's process()
// function.
audit.define('process-error',
(task, should) => {
let context = new OfflineAudioContext(1, renderLength, sampleRate);
context.audioWorklet.addModule('state-processor.js').then(() => {
let processErrorWorkletNode =
new AudioWorkletNode(context, 'process-error');
should(processErrorWorkletNode.processorState,
'processErrorWorkletNode.processorState after ' +
'its construction')
.beEqualTo('pending');
processErrorWorkletNode.connect(context.destination);
let isFirstPhase = true;
processErrorWorkletNode.onprocessorstatechange = () => {
if (isFirstPhase) {
// Ignore the first state change event, which is "running";
isFirstPhase = false;
} else {
should(processErrorWorkletNode.processorState,
'workletNode.processorState upon processorstatechange ' +
'event after the failure from processor.process()')
.beEqualTo('error');
task.done();
}
};
context.startRendering();
});
});
audit.run();
</script>
</body>
</html>