blob: 3c9f1fb4d523d31e29f039d0a096a90fa9c2ffb7 [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 disconnect() method on AudioParam destination.');
window.jsTestIsAsync = true;
var audit = Audit.createTaskRunner();
// The long render length (20 seconds) test 1 and 2 is to make sure the
// |onstatechange| event gets fired to start the source, which can take
// quite a bit of time.
var testDuration = 20;
// Task 1: test disconnect(AudioParam) method.
audit.defineTask('disconnect(AudioParam)', function (done) {
// Creates a buffer source with value [1] and then connect it to two gain
// nodes in series. The output of the buffer source is lowered by half
// (* 0.5) and then connected to two |.gain| AudioParams in each gain node.
// (1) bufferSource => gain1 => gain2
// (2) bufferSource => half => gain1.gain
// (3) half => gain2.gain
// This graph should produce the output of 2.25 (= 1 * 1.5 * 1.5). After
// disconnecting (3), it should produce 1.5.
var context = new OfflineAudioContext(1, 44100 * testDuration, 44100);
var source = context.createBufferSource();
var buffer1ch = createTestingAudioBuffer(context, 1, 128);
var half = context.createGain();
var gain1 = context.createGain();
var gain2 = context.createGain();
source.buffer = buffer1ch;
source.loop = true;
half.gain.value = 0.5;
source.connect(gain1);
gain1.connect(gain2);
gain2.connect(context.destination);
source.connect(half);
// Connecting |half| to both |gain1.gain| and |gain2.gain| amplifies the
// signal by 2.25 (= 1.5 * 1.5) because each gain node amplifies the signal
// by 1.5 (= 1.0 + 0.5).
half.connect(gain1.gain);
half.connect(gain2.gain);
source.start();
// Disconnects after the rendering starts.
//
// FIXME: Although this guarantees that the disconnection happens after
// the rendering starts, still the actual disconnection might happen after
// oncomplete event fired.
//
// The 10ms delay is 1/1000 of the total render length (10,000ms). Because
// OfflineAudioContext runs faster than real time, the disconnection might
// happen after the rendering finishes. Then lower the delay and increase
// the render length to avoid the test failure.
context.onstatechange = function () {
if (context.state === 'running')
half.disconnect(gain2.gain);
};
context.startRendering().then(function (buffer) {
// Note that this test depends on the disconnection below to happen
// sometime during rendering.
// Expected values are: 1 * 1.5 * 1.5 -> 1 * 1.5 = [2.25, 1.5]
Should('Channel #0', buffer.getChannelData(0)).containValues([2.25, 1.5]);
}).then(done);
});
// Task 2: test disconnect(AudioParam, output) method.
audit.defineTask('disconnect(AudioParam, output)', function (done) {
// Create a 2-channel buffer source with [1, 2] in each channel and
// make a serial connection through gain1 and gain 2. The make the buffer
// source half with a gain node and connect it to a 2-output splitter.
// Connect each output to 2 gain AudioParams respectively.
// (1) bufferSource => gain1 => gain2
// (2) bufferSource => half => splitter(2)
// (3) splitter#0 => gain1.gain
// (4) splitter#1 => gain2.gain
// This graph should produce 3 (= 1 * 1.5 * 2) and 6 (= 2 * 1.5 * 2) for
// each channel. After disconnecting (4), it should output 1.5 and 3.
var context = new OfflineAudioContext(2, 44100 * testDuration, 44100);
var source = context.createBufferSource();
var buffer2ch = createTestingAudioBuffer(context, 2, 128);
var splitter = context.createChannelSplitter(2);
var half = context.createGain();
var gain1 = context.createGain();
var gain2 = context.createGain();
source.buffer = buffer2ch;
source.loop = true;
half.gain.value = 0.5;
source.connect(gain1);
gain1.connect(gain2);
gain2.connect(context.destination);
// |source| originally is [1, 2] but it becomes [0.5, 1] after 0.5 gain.
// Each splitter's output will be applied to |gain1.gain| and |gain2.gain|
// respectively in an additive fashion.
source.connect(half);
half.connect(splitter);
// This amplifies the signal by 1.5. (= 1.0 + 0.5)
splitter.connect(gain1.gain, 0);
// This amplifies the signal by 2. (= 1.0 + 1.0)
splitter.connect(gain2.gain, 1);
source.start();
// Disconnect after the rendering starts. See the comment in the previous
// test task.
context.onstatechange = function () {
if (context.state === 'running')
splitter.disconnect(gain2.gain, 1);
};
context.startRendering().then(function (buffer) {
// Expected values are: 1 * 1.5 * 2 -> 1 * 1.5 = [3, 1.5]
Should('Channel #0', buffer.getChannelData(0)).containValues([3, 1.5]);
// Expected values are: 2 * 1.5 * 2 -> 2 * 1.5 = [6, 3]
Should('Channel #1', buffer.getChannelData(1)).containValues([6, 3]);
}).then(done);
});
// Task 3: exception checks.
audit.defineTask('exceptions', function (done) {
var context = new AudioContext();
var gain1 = context.createGain();
var splitter = context.createChannelSplitter(2);
var gain2 = context.createGain();
var gain3 = context.createGain();
// Connect a splitter to gain nodes and merger so we can test the possible
// ways of disconnecting the nodes to verify that appropriate exceptions
// are thrown.
gain1.connect(splitter);
splitter.connect(gain2.gain, 0);
splitter.connect(gain3.gain, 1);
gain2.connect(gain3);
gain3.connect(context.destination);
// gain1 is not connected to gain3.gain. Exception should be thrown.
Should('gain1.disconnect(gain3.gain)', function () {
gain1.disconnect(gain3.gain);
}).throw('InvalidAccessError');
// When the output index is good but the destination is invalid.
Should('splitter.disconnect(gain1.gain, 1)', function () {
splitter.disconnect(gain1.gain, 1);
}).throw('InvalidAccessError');
// When both arguments are wrong, throw IndexSizeError first.
Should('splitter.disconnect(gain1.gain, 2)', function () {
splitter.disconnect(gain1.gain, 2);
}).throw('IndexSizeError');
done();
});
audit.defineTask('finish', function (done) {
finishJSTest();
done();
});
audit.runTasks(
'disconnect(AudioParam)',
'disconnect(AudioParam, output)',
'exceptions',
'finish'
);
successfullyParsed = true;
</script>
</body>
</html>