<!DOCTYPE html>
<html>
<head>
<title>
Handle Silent Inputs to AnalyserNode
</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../resources/audit-util.js"></script>
<script src="../resources/audit.js"></script>
</head>
<body>
<script id="layout-test-code">
let audit = Audit.createTaskRunner();
let sampleRate = 16000;
let renderDuration = 1;
let renderFrames = renderDuration * sampleRate;
audit.define(
{label: 'connected', description: 'Test handling of silent inputs'},
function(task, should) {
tester(should, false, '0').then(task.done.bind(task));
});
audit.define(
{label: 'auto-pull', description: 'Test handling of silent inputs'},
function(task, should) {
tester(should, true, '1').then(task.done.bind(task));
});
audit.define(
{
label: 'timing',
description: 'Test shifting in of zeroes after source has stopped'
},
function(task, should) {
let renderQuantumFrames = 128;
// sampleRate chosen to be a power of two so we don't have round-off
// errors in computing the times for when to suspend the context.
let context = new OfflineAudioContext(1, 16384, 16384);
let source = new ConstantSourceNode(context);
// The fftSize for the analyser is fairly arbitrary, except the code
// assumes it is larger than 128.
let analyser = new AnalyserNode(context, {fftSize: 2048});
source.connect(analyser).connect(context.destination);
source.start();
// Stop the source after 1 fftSize frames.
let time = analyser.fftSize / context.sampleRate;
source.stop(time);
// Verify that the time data at this point is constant.
context.suspend(time)
.then(() => {
let data = new Float32Array(analyser.fftSize);
analyser.getFloatTimeDomainData(data);
should(
data,
'At time ' + context.currentTime +
' Analyser frames [0, ' + analyser.fftSize + ')')
.beConstantValueOf(1);
})
.then(context.resume.bind(context));
// After each rendering quantum from the point at which the source
// stopped, verify that zeroes are inserted into the time data one
// rendering quantum at a time.
let limit = analyser.fftSize / renderQuantumFrames;
for (let k = 1; k <= limit; ++k) {
let analyserTime = (analyser.fftSize + k * renderQuantumFrames) /
context.sampleRate;
context.suspend(analyserTime)
.then(() => {
let data = new Float32Array(analyser.fftSize);
let indexNewest =
analyser.fftSize - k * renderQuantumFrames;
analyser.getFloatTimeDomainData(data);
if (k < limit) {
should(
data.slice(0, indexNewest),
'At time ' + context.currentTime +
' Analyser frames [0, ' + indexNewest + ')')
.beConstantValueOf(1);
}
should(
data.slice(indexNewest),
'At time ' + context.currentTime +
' Analyser frames [' + indexNewest + ', ' +
analyser.fftSize + ')')
.beConstantValueOf(0);
})
.then(context.resume.bind(context));
}
// Start the test
context.startRendering().then(() => task.done());
});
audit.run();
function tester(should, isAutoPullTest, prefix) {
// Connect an oscillator to an analyser for testing the time data of the
// analyser after the oscillator stops.
let context = new OfflineAudioContext(1, renderFrames, sampleRate);
let source = new OscillatorNode(context);
let analyser = new AnalyserNode(context, {fftSize: 128});
let timeData = new Float32Array(analyser.fftSize);
timeData.fill(NaN);
source.connect(analyser);
// For the automatic pull test, leave the analyser output disconnected.
if (isAutoPullTest) {
source.connect(context.destination);
} else {
analyser.connect(context.destination);
}
source.start();
// Stop the source well in advance of when we want to get the time data
// from the analyser.
let stopTime = 0.1;
let dataTime = 0.5;
source.stop(stopTime);
context.suspend(dataTime)
.then(() => {
analyser.getFloatTimeDomainData(timeData);
})
.then(context.resume.bind(context));
return context.startRendering().then(buffer => {
should(timeData, prefix + ': Analyser time data at time ' + dataTime)
.beConstantValueOf(0);
});
}
</script>
</body>
</html>