blob: eb06ec2f65f4cf3e260b3dd7744dbade672c614e [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<script src="../resources/js-test.js"></script>
<script src="resources/compatibility.js"></script>
<script src="resources/audio-testing.js"></script>
</head>
<body>
<script>
description('Test method chaining feature of AudioNode.connect() method.');
window.jsTestIsAsync = true;
// AudioNode dictionary with associated arguments.
var nodeDictionary = [
{ name: 'Analyser' },
{ name: 'BiquadFilter' },
{ name: 'BufferSource' },
{ name: 'ChannelMerger', args: [6] },
{ name: 'ChannelSplitter', args: [6] },
{ name: 'Convolver' },
{ name: 'Delay', args: [] },
{ name: 'DynamicsCompressor' },
{ name: 'Gain' },
{ name: 'Oscillator' },
{ name: 'Panner' },
{ name: 'ScriptProcessor', args: [512, 1, 1] },
{ name: 'StereoPanner' },
{ name: 'WaveShaper' }
];
function verifyReturnedNode(config) {
if (config.destination === config.returned) {
testPassed('The return value of ' + config.desc + ' matches the destination ' +
config.returned.constructor.name + '.');
} else {
testFailed('The return value of ' + config.desc + ' does NOT match the destination ' +
config.destination.constructor.name + '.');
}
}
// Test utility for batch method checking: in order to test 3 method
// signatures, so we create 3 dummy destinations.
// 1) .connect(GainNode)
// 2) .connect(BiquadFilterNode, output)
// 3) .connect(ChannelMergerNode, output, input)
function testConnectMethod(context, options) {
var source = context['create' + options.name].apply(context, options.args);
var sourceName = source.constructor.name;
var destination1 = context.createGain();
verifyReturnedNode({
source: source,
destination: destination1,
returned: source.connect(destination1),
desc: sourceName + '.connect(' + destination1.constructor.name + ')'
});
var destination2 = context.createBiquadFilter();
verifyReturnedNode({
source: source,
destination: destination2,
returned: source.connect(destination2, 0),
desc: sourceName + '.connect(' + destination2.constructor.name + ', 0)'
});
var destination3 = context.createChannelMerger();
verifyReturnedNode({
source: source,
destination: destination3,
returned: source.connect(destination3, 0, 1),
desc: sourceName + '.connect(' + destination3.constructor.name + ', 0, 1)'
});
}
var audit = Audit.createTaskRunner();
// Task: testing entries from the dictionary.
audit.defineTask('from-dictionary', function (done) {
var context = new AudioContext();
for (var i = 0; i < nodeDictionary.length; i++)
testConnectMethod(context, nodeDictionary[i]);
done();
});
// Task: testing Media* nodes.
audit.defineTask('media-group', function (done) {
var context = new AudioContext();
// Test MediaElementSourceNode needs an <audio> element.
var mediaElement = document.createElement('audio');
testConnectMethod(context, { name: 'MediaElementSource', args: [mediaElement] });
testConnectMethod(context, { name: 'MediaStreamDestination' });
// MediaStreamSourceNode requires 'stream' object to be constructed, which
// is a part of MediaStreamDestinationNode.
var streamDestination = context.createMediaStreamDestination();
var stream = streamDestination.stream;
testConnectMethod(context, { name: 'MediaStreamSource', args: [stream] });
done();
});
// Task: test the exception thrown by invalid operation.
audit.defineTask('invalid-operation', function (done) {
var contextA = new AudioContext();
var contextB = new AudioContext();
var gain1 = contextA.createGain();
var gain2 = contextA.createGain();
// Test if the first connection throws correctly. The first gain node does
// not have the second output, so it should throw.
Should('Connecting with an invalid output', function () {
gain1.connect(gain2, 1).connect(contextA.destination);
}).throw('IndexSizeError');
// Test if the second connection throws correctly. The contextB's
// destination is not compatible with the nodes from contextA, thus the
// first connection succeeds but the second one should throw.
Should('Connecting to a node from the different context', function () {
gain1.connect(gain2).connect(contextB.destination);
}).throw('SyntaxError');
done();
});
// Task: verify if the method chaining actually works.
audit.defineTask('verification', function (done) {
// We pick the lowest sample rate allowed to run the test efficiently.
var context = new OfflineAudioContext(1, 128, 3000);
var constantBuffer = createConstantBuffer(context, 1, 1.0);
var source = context.createBufferSource();
source.buffer = constantBuffer;
source.loop = true;
var gain1 = context.createGain();
gain1.gain.value = 0.5;
var gain2 = context.createGain();
gain2.gain.value = 0.25;
source.connect(gain1).connect(gain2).connect(context.destination);
source.start();
context.startRendering().then(function (buffer) {
Should('The output of chained connection of gain nodes', buffer.getChannelData(0))
.beConstantValueOf(0.125);
}).then(done);
});
audit.defineTask('finish', function (done) {
finishJSTest();
done();
});
audit.runTasks(
'from-dictionary',
'media-group',
'invalid-operation',
'verification',
'finish'
);
successfullyParsed = true;
</script>
</body>
</html>