165 lines
5.9 KiB
HTML
165 lines
5.9 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>
|
|
audionode-connect-method-chaining.html
|
|
</title>
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="/webaudio/resources/audit-util.js"></script>
|
|
<script src="/webaudio/resources/audit.js"></script>
|
|
</head>
|
|
<body>
|
|
<script id="layout-test-code">
|
|
// AudioNode dictionary with associated arguments.
|
|
let 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(should, config) {
|
|
should(
|
|
config.destination === config.returned,
|
|
'The return value of ' + config.desc + ' matches the destination ' +
|
|
config.returned.constructor.name)
|
|
.beEqualTo(true);
|
|
}
|
|
|
|
// 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, should, options) {
|
|
let source =
|
|
context['create' + options.name].apply(context, options.args);
|
|
let sourceName = source.constructor.name;
|
|
|
|
let destination1 = context.createGain();
|
|
verifyReturnedNode(should, {
|
|
source: source,
|
|
destination: destination1,
|
|
returned: source.connect(destination1),
|
|
desc: sourceName + '.connect(' + destination1.constructor.name + ')'
|
|
});
|
|
|
|
let destination2 = context.createBiquadFilter();
|
|
verifyReturnedNode(should, {
|
|
source: source,
|
|
destination: destination2,
|
|
returned: source.connect(destination2, 0),
|
|
desc:
|
|
sourceName + '.connect(' + destination2.constructor.name + ', 0)'
|
|
});
|
|
|
|
let destination3 = context.createChannelMerger();
|
|
verifyReturnedNode(should, {
|
|
source: source,
|
|
destination: destination3,
|
|
returned: source.connect(destination3, 0, 1),
|
|
desc: sourceName + '.connect(' + destination3.constructor.name +
|
|
', 0, 1)'
|
|
});
|
|
}
|
|
|
|
|
|
let audit = Audit.createTaskRunner();
|
|
|
|
// Task: testing entries from the dictionary.
|
|
audit.define('from-dictionary', (task, should) => {
|
|
let context = new AudioContext();
|
|
|
|
for (let i = 0; i < nodeDictionary.length; i++)
|
|
testConnectMethod(context, should, nodeDictionary[i]);
|
|
|
|
task.done();
|
|
});
|
|
|
|
// Task: testing Media* nodes.
|
|
audit.define('media-group', (task, should) => {
|
|
let context = new AudioContext();
|
|
|
|
// Test MediaElementSourceNode needs an <audio> element.
|
|
let mediaElement = document.createElement('audio');
|
|
testConnectMethod(
|
|
context, should,
|
|
{name: 'MediaElementSource', args: [mediaElement]});
|
|
|
|
// MediaStreamAudioDestinationNode has no output so it connect method
|
|
// chaining isn't possible.
|
|
|
|
// MediaStreamSourceNode requires 'stream' object to be constructed,
|
|
// which is a part of MediaStreamDestinationNode.
|
|
let streamDestination = context.createMediaStreamDestination();
|
|
let stream = streamDestination.stream;
|
|
testConnectMethod(
|
|
context, should, {name: 'MediaStreamSource', args: [stream]});
|
|
|
|
task.done();
|
|
});
|
|
|
|
// Task: test the exception thrown by invalid operation.
|
|
audit.define('invalid-operation', (task, should) => {
|
|
let contextA = new AudioContext();
|
|
let contextB = new AudioContext();
|
|
let gain1 = contextA.createGain();
|
|
let 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(function() {
|
|
gain1.connect(gain2, 1).connect(contextA.destination);
|
|
}, 'Connecting with an invalid output').throw(DOMException, '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(
|
|
function() {
|
|
gain1.connect(gain2).connect(contextB.destination);
|
|
},
|
|
'Connecting to a node from the different context')
|
|
.throw(DOMException, 'InvalidAccessError');
|
|
|
|
task.done();
|
|
});
|
|
|
|
// Task: verify if the method chaining actually works.
|
|
audit.define('verification', (task, should) => {
|
|
// We pick the lowest sample rate allowed to run the test efficiently.
|
|
let context = new OfflineAudioContext(1, 128, 8000);
|
|
|
|
let constantBuffer = createConstantBuffer(context, 1, 1.0);
|
|
|
|
let source = context.createBufferSource();
|
|
source.buffer = constantBuffer;
|
|
source.loop = true;
|
|
|
|
let gain1 = context.createGain();
|
|
gain1.gain.value = 0.5;
|
|
let gain2 = context.createGain();
|
|
gain2.gain.value = 0.25;
|
|
|
|
source.connect(gain1).connect(gain2).connect(context.destination);
|
|
source.start();
|
|
|
|
context.startRendering()
|
|
.then(function(buffer) {
|
|
should(
|
|
buffer.getChannelData(0),
|
|
'The output of chained connection of gain nodes')
|
|
.beConstantValueOf(0.125);
|
|
})
|
|
.then(() => task.done());
|
|
});
|
|
|
|
audit.run();
|
|
</script>
|
|
</body>
|
|
</html>
|