Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test has a WPT meta file that expects 2 subtest issues.
- This WPT test may be referenced by the following Test IDs:
- /webaudio/the-audio-api/the-audionode-interface/audionode-disconnect-audioparam.html - WPT Dashboard Interop Dashboard
<!DOCTYPE html>
<html>
<head>
<title>
audionode-disconnect-audioparam.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">
let renderQuantum = 128;
let sampleRate = 44100;
let renderDuration = 0.5;
let disconnectTime = 0.5 * renderDuration;
let audit = Audit.createTaskRunner();
// Calculate the index for disconnection.
function getDisconnectIndex(disconnectTime) {
let disconnectIndex = disconnectTime * sampleRate;
disconnectIndex = renderQuantum *
Math.floor((disconnectIndex + renderQuantum - 1) / renderQuantum);
return disconnectIndex;
}
// Get the index of value change.
function getValueChangeIndex(array, targetValue) {
return array.findIndex(function(element, index) {
if (element === targetValue)
return true;
});
}
// Task 1: test disconnect(AudioParam) method.
audit.define('disconnect(AudioParam)', (task, should) => {
// 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.
let context =
new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
let source = context.createBufferSource();
let buffer1ch = createConstantBuffer(context, 1, 1);
let half = context.createGain();
let gain1 = context.createGain();
let 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();
// Schedule the disconnection at the half of render duration.
context.suspend(disconnectTime).then(function() {
half.disconnect(gain2.gain);
context.resume();
});
context.startRendering()
.then(function(buffer) {
let channelData = buffer.getChannelData(0);
let disconnectIndex = getDisconnectIndex(disconnectTime);
let valueChangeIndex = getValueChangeIndex(channelData, 1.5);
// Expected values are: 1 * 1.5 * 1.5 -> 1 * 1.5 = [2.25, 1.5]
should(channelData, 'Channel #0').containValues([2.25, 1.5]);
should(valueChangeIndex, 'The index of value change')
.beEqualTo(disconnectIndex);
})
.then(() => task.done());
});
// Task 2: test disconnect(AudioParam, output) method.
audit.define('disconnect(AudioParam, output)', (task, should) => {
// 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.
let context =
new OfflineAudioContext(2, renderDuration * sampleRate, sampleRate);
let source = context.createBufferSource();
let buffer2ch = createConstantBuffer(context, 1, [1, 2]);
let splitter = context.createChannelSplitter(2);
let half = context.createGain();
let gain1 = context.createGain();
let 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();
// Schedule the disconnection at the half of render duration.
context.suspend(disconnectTime).then(function() {
splitter.disconnect(gain2.gain, 1);
context.resume();
});
context.startRendering()
.then(function(buffer) {
let channelData0 = buffer.getChannelData(0);
let channelData1 = buffer.getChannelData(1);
let disconnectIndex = getDisconnectIndex(disconnectTime);
let valueChangeIndexCh0 = getValueChangeIndex(channelData0, 1.5);
let valueChangeIndexCh1 = getValueChangeIndex(channelData1, 3);
// Expected values are: 1 * 1.5 * 2 -> 1 * 1.5 = [3, 1.5]
should(channelData0, 'Channel #0').containValues([3, 1.5]);
should(
valueChangeIndexCh0,
'The index of value change in channel #0')
.beEqualTo(disconnectIndex);
// Expected values are: 2 * 1.5 * 2 -> 2 * 1.5 = [6, 3]
should(channelData1, 'Channel #1').containValues([6, 3]);
should(
valueChangeIndexCh1,
'The index of value change in channel #1')
.beEqualTo(disconnectIndex);
})
.then(() => task.done());
});
// Task 3: exception checks.
audit.define('exceptions', (task, should) => {
let context = new AudioContext();
let gain1 = context.createGain();
let splitter = context.createChannelSplitter(2);
let gain2 = context.createGain();
let 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(
function() {
gain1.disconnect(gain3.gain);
},
'gain1.disconnect(gain3.gain)')
.throw(DOMException, 'InvalidAccessError');
// When the output index is good but the destination is invalid.
should(
function() {
splitter.disconnect(gain1.gain, 1);
},
'splitter.disconnect(gain1.gain, 1)')
.throw(DOMException, 'InvalidAccessError');
// When both arguments are wrong, throw IndexSizeError first.
should(
function() {
splitter.disconnect(gain1.gain, 2);
},
'splitter.disconnect(gain1.gain, 2)')
.throw(DOMException, 'IndexSizeError');
task.done();
});
audit.run();
</script>
</body>
</html>