| Index: LayoutTests/webaudio/audionode-disconnect-audioparam.html
|
| diff --git a/LayoutTests/webaudio/audionode-disconnect-audioparam.html b/LayoutTests/webaudio/audionode-disconnect-audioparam.html
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b9a31aec4fc61fff4fb0d03b37b89dae9e13d707
|
| --- /dev/null
|
| +++ b/LayoutTests/webaudio/audionode-disconnect-audioparam.html
|
| @@ -0,0 +1,237 @@
|
| +<!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();
|
| +
|
| + // 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 * 10, 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.
|
| + var stateAlreadyChanged = false;
|
| + context.onstatechange = function () {
|
| + if (!stateAlreadyChanged) {
|
| + half.disconnect(gain2.gain);
|
| + stateAlreadyChanged = true;
|
| + }
|
| + };
|
| +
|
| + context.startRendering().then(function (buffer) {
|
| +
|
| + // Note that this test depends on the disconnection below to happen
|
| + // sometime during rendering.
|
| + var channelData = buffer.getChannelData(0);
|
| + var expectedValues = [2.25, 1.5]; // 1 * 1.5 * 1.5 -> 1 * 1.5
|
| + var passed = compareElements(expectedValues, channelData);
|
| +
|
| + if (passed) {
|
| + testPassed('The rendered buffer matches expected values: [' +
|
| + expectedValues.toString() + ']'
|
| + );
|
| + } else {
|
| + testFailed('The rendered buffer does not match expected values.');
|
| + }
|
| + }).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 * 10, 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.
|
| + var stateAlreadyChanged = false;
|
| + context.onstatechange = function () {
|
| + if (!stateAlreadyChanged) {
|
| + splitter.disconnect(gain2.gain, 1);
|
| + stateAlreadyChanged = true;
|
| + }
|
| + };
|
| +
|
| + context.startRendering().then(function (buffer) {
|
| + var channelData0 = buffer.getChannelData(0);
|
| + var channelData1 = buffer.getChannelData(1);
|
| + var expectedValuesCh0 = [3, 1.5]; // 1 * 1.5 * 2 -> 1 * 1.5
|
| + var expectedValuesCh1 = [6, 3]; // 2 * 1.5 * 2 -> 2 * 1.5
|
| + var passedCh0 = compareElements(expectedValuesCh0, channelData0);
|
| + var passedCh1 = compareElements(expectedValuesCh1, channelData1);
|
| +
|
| + if (passedCh0 && passedCh1) {
|
| + testPassed('The rendered buffer matches expected values: Ch0 = [' +
|
| + expectedValuesCh0.toString() + '] Ch1 = [' + expectedValuesCh1.toString() +
|
| + ']'
|
| + );
|
| + } else {
|
| + testFailed('Expected values do not match.');
|
| + }
|
| + }).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.throwWithType('InvalidAccessError', function () {
|
| + gain1.disconnect(gain3.gain);
|
| + });
|
| +
|
| + // When the output index is good but the destination is invalid.
|
| + Should.throwWithType('InvalidAccessError', function () {
|
| + splitter.disconnect(gain1.gain, 1);
|
| + });
|
| +
|
| + // When both arguments are wrong, throw IndexSizeError first.
|
| + Should.throwWithType('IndexSizeError', function () {
|
| + splitter.disconnect(gain1.gain, 2);
|
| + });
|
| +
|
| + done();
|
| + });
|
| +
|
| + audit.defineTask('finish', function (done) {
|
| + finishJSTest();
|
| + done();
|
| + });
|
| +
|
| + audit.runTasks(
|
| + 'disconnect(AudioParam)',
|
| + 'disconnect(AudioParam, output)',
|
| + 'exceptions',
|
| + 'finish'
|
| + );
|
| +
|
| + // The value-wise comparison of two arrays with different length. It
|
| + // checks the value of element regardless of its occurrence. For example,
|
| + // (1) [2.25, 2.25, 2.25, 1.5, 1.5, 1.5] === [2.25, 1.5]
|
| + // (2) [2.25, 2.25, 1.5, 1.5, 0, 7, 7, 7, 9, 1] !== [2.25, 1.5]
|
| + // (3) [-1, 2, 3, 2.25, 2.25, 1.5, 1.5] !== [2.25, 1.5]
|
| + // (4) [3, 3, 3, 7, 7, 7] !== [2.25, 1.5]
|
| + function compareElements(expected, actual) {
|
| + var indexExpected = 0, indexActual = 0;
|
| + while (indexExpected < expected.length && indexActual < actual.length) {
|
| + if (expected[indexExpected] === actual[indexActual]) {
|
| + indexActual++;
|
| + } else {
|
| + indexExpected++;
|
| + }
|
| + }
|
| +
|
| + if (indexExpected < expected.length - 1 || indexActual < actual.length - 1) {
|
| + // This is for the debugging purpose. Printed out only when failed.
|
| + console.log('The value ' + actual[indexActual] + ' at index ' +
|
| + indexActual + ' was not found in expected values');
|
| + return false;
|
| + } else {
|
| + return true;
|
| + }
|
| + }
|
| +
|
| + successfullyParsed = true;
|
| + </script>
|
| +</body>
|
| +
|
| +</html>
|
|
|