blob: afea8f68cfc46bb5f618349ca0424bfdd677fd5c [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<script src="resources/compatibility.js"></script>
<script src="resources/audio-testing.js"></script>
<script src="../resources/js-test.js"></script>
<script src="resources/biquad-testing.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script>
description("Tests DOM exception messages");
var context;
var otherContext;
var node;
var node2;
var mode;
var panner;
var script;
function shouldThrowAndBeUnchanged(attr, value) {
shouldThrow(attr + " = " + value);
shouldNotBe(attr, value);
}
function runTest() {
if (window.testRunner) {
testRunner.dumpAsText();
}
context = new AudioContext();
otherContext = new AudioContext();
// Test creation of various objects
// Invalid number of channels: NotSupportedError
shouldThrow("context.createBuffer(99, 1, context.sampleRate)");
shouldThrow("context.createBuffer(0, 1, context.sampleRate)");
// Invalid sample rate: NotSupportedError
shouldThrow("context.createBuffer(1, 1, 1)");
shouldThrow("context.createBuffer(1, 1, 1e6)");
// Check valid values from crbug.com/344375
shouldNotThrow("context.createBuffer(1, 1, 3000)");
shouldNotThrow("context.createBuffer(1, 1, 192000)");
// Invalid number of frames: NotSupportedError
shouldThrow("context.createBuffer(1, 0, context.sampleRate)");
// 2-arg createBuffer not allowed.
shouldThrow("context.createBuffer(new ArrayBuffer(100), true)");
// Invalid sources (unspecified error)
shouldThrow("context.createMediaElementSource(null)");
shouldThrow("context.createMediaStreamSource(null)");
// Invalid buffer size: IndexSizeError
shouldThrow("context.createScriptProcessor(1, 1, 1)");
// Invalid number of inputs and outputs: IndexSizeError
shouldThrow("context.createScriptProcessor(4096, 100, 1)");
shouldThrow("context.createScriptProcessor(4096, 1, 100)");
shouldNotThrow("context.createScriptProcessor()");
shouldNotThrow("context.createScriptProcessor(0)");
// Invalid number of channels: IndexSizeError
shouldThrow("context.createChannelSplitter(0)");
shouldThrow("context.createChannelSplitter(99)");
shouldThrow("context.createChannelMerger(0)");
shouldThrow("context.createChannelMerger(99)");
// Invalid real/imag arrays: IndexSizeError
shouldThrow("context.createPeriodicWave(null, null)");
shouldThrow("context.createPeriodicWave(new Float32Array(10), null)");
// Verify that we can use large arrays with no limit. Roughly.
shouldNotThrow("context.createPeriodicWave(new Float32Array(4100), new Float32Array(4100))");
shouldNotThrow("context.createPeriodicWave(new Float32Array(8192), new Float32Array(8192))");
shouldNotThrow("context.createPeriodicWave(new Float32Array(10000), new Float32Array(10000))");
// Real and imaginary arrays must have the same size: IndexSizeError
shouldThrow("context.createPeriodicWave(new Float32Array(10), new Float32Array(7))");
// Analysers
node = context.createAnalyser();
// Invalid fftSize: IndexSizeError
shouldThrowAndBeUnchanged("node.fftSize", "42");
shouldThrowAndBeUnchanged("node.fftSize", "16");
shouldNotThrow("node.fftSize = 32768");
shouldThrowAndBeUnchanged("node.fftSize", "65536");
shouldThrowAndBeUnchanged("node.minDecibels", "-10");
shouldThrowAndBeUnchanged("node.maxDecibels", "-150");
shouldThrowAndBeUnchanged("node.minDecibels", "-30");
shouldThrowAndBeUnchanged("node.maxDecibels", "-100");
shouldThrowAndBeUnchanged("node.smoothingTimeConstant", "-0.1");
shouldThrowAndBeUnchanged("node.smoothingTimeConstant", "1.5");
shouldThrow("node.getFloatFrequencyData(null)");
shouldThrow("node.getByteFrequencyData(null)");
shouldThrow("node.getFloatTimeDomainData(null)");
shouldThrow("node.getByteTimeDomainData(null)");
// AudioBuffers
node = context.createBuffer(1,1, context.sampleRate);
// Invalid channel index: IndexSizeError
shouldThrow("node.getChannelData(2)");
// AudioNode connections
node = context.createGain();
node2 = context.createGain();
// Invalid destination node (unspecified error)
shouldThrow("node.connect(null, 0, 0)");
// Invalid input or output index: IndexSizeError
shouldThrow("node.connect(context.destination, 100, 0)");
shouldThrow("node.connect(context.destination, 0, 100)");
shouldThrow("node.connect(node2.gain, 100)");
shouldThrow("node.disconnect(99)");
// Can't connect to a different context (unspecified error)
shouldThrow("node.connect(otherContext.destination)");
// Invalid channel count: NotSupportedError
shouldThrowAndBeUnchanged("node.channelCount", "99");
// Invalid mode or interpretation (unspecified error)
currentMode = node.channelCountMode;
currentInterpretation = node.channelInterpretation;
shouldNotThrow("node.channelCountMode = 'fancy'");
if (node.channelCountMode == currentMode)
testPassed("Invalid channelCountMode value did not change mode");
else
testFailed("node.channelCountMode incorrectly changed to invalid value " + node.channelCountMode);
shouldNotThrow("node.channelInterpretation = mode");
if (node.channelInterpretation == currentInterpretation)
testPassed("Invalid channelInterpration value did not change mode");
else
testFailed("node.channelInterpretation incorrectly changed to invalid value " + node.channelInterpreation);
// Destination node channel count: should throw IndexSizeError on invalid
// channel count. shouldNotThrow() method cannot be used because the error
// message includes the number of channels, which can change depending on
// the actual attached hardware.
try {
eval("context.destination.channelCount = 99");
} catch (e) {
if (e.message === "Failed to set the 'channelCount' property on 'AudioNode': The channel count provided (99) is outside the range [1, " + context.destination.maxChannelCount + "]." && e.name === "IndexSizeError")
testPassed("context.destination.channelCount = 99 threw IndexSizeError exception on invalid channel count.");
else
testFailed("context.destination.channelCount = 99 should throw IndexSizeError exception on invalid channel count.");
}
// AudioParams
param = context.createGain().gain;
shouldThrow("param.setValueCurveAtTime(null, 0, 0)");
// BiquadFilterNode
node = context.createBiquadFilter();
shouldNotThrow("node.getFrequencyResponse(new Float32Array(1), new Float32Array(1), new Float32Array(1))");
shouldThrow("node.getFrequencyResponse(null, new Float32Array(1), new Float32Array(1))");
shouldThrow("node.getFrequencyResponse(new Float32Array(1), null, new Float32Array(1))");
shouldThrow("node.getFrequencyResponse(new Float32Array(1), new Float32Array(1), null)");
// Delay nodes are tested elsewhere, so don't duplicate that work here.
// OfflineAudioContext
// Max supported channels
shouldNotThrow("new OfflineAudioContext(32, 100, context.sampleRate)");
// Invalid number of channels (unspecified error)
shouldThrow("new OfflineAudioContext(99, 100, context.sampleRate)");
// Invalid sample rate. (unspecified error)
shouldThrow("new OfflineAudioContext(1, 100, 1)");
shouldThrow("new OfflineAudioContext(1, 100, 1e6)");
// Invalid frame length (crbug.com/351277)
shouldThrow("new OfflineAudioContext(1, -88200000000000, 44100)");
// WaveShaper types
node = context.createWaveShaper();
currentOversample = node.oversample;
shouldNotThrow("node.oversample = '9x'");
if (node.oversample == currentOversample)
testPassed("Invalid oversample value did not change node.oversample");
else
testFailed("node.oversample incorrectly changed to invalid value " + node.oversample);
shouldThrow("node.curve = {}");
shouldThrow("node.curve = new Float32Array(1)");
shouldBeNull("node.curve");
shouldNotThrow("node.curve = new Float32Array(2)");
shouldNotThrow("node.curve = null");
// Start/stop for AudioBufferSourceNodes
buffer = context.createBuffer(1,1, context.sampleRate);
shouldNotThrow("source = context.createBufferSource()");
shouldNotThrow("source.buffer = buffer");
shouldThrow("source.buffer = context.createBuffer(1, 10, context.sampleRate)");
shouldThrow("source.start(-1)");
shouldThrow("source.start(Infinity)");
shouldThrow("source.start(-Infinity)");
shouldThrow("source.start(NaN)");
shouldThrow("source.start(1, Infinity)");
shouldThrow("source.start(1, -Infinity)");
shouldThrow("source.start(1, NaN)");
shouldThrow("source.start(1, -1)");
shouldThrow("source.start(1, -Number.MIN_VALUE)");
shouldThrow("source.start(1, 1, Infinity)");
shouldThrow("source.start(1, 1, -Infinity)");
shouldThrow("source.start(1, 1, NaN)");
shouldThrow("source.start(1, 1, -1)");
shouldThrow("source.start(1, 1, -Number.MIN_VALUE)");
shouldNotThrow("source.start()");
shouldThrow("source.stop(-Number.MIN_VALUE)");
shouldThrow("source.stop(Infinity)");
shouldThrow("source.stop(-Infinity)");
shouldThrow("source.stop(NaN)");
shouldNotThrow("source.stop()");
// Verify that start(0, 0) doesn't signal.
shouldNotThrow("source = context.createBufferSource()");
shouldNotThrow("source.buffer = buffer");
shouldNotThrow("source.start(0, 0)");
// Verify that start(0, -0.0) doesn't signal.
shouldNotThrow("source = context.createBufferSource()");
shouldNotThrow("source.buffer = buffer");
shouldNotThrow("source.start(0, -1/Infinity)");
// It's not clear from the spec, but I think it's valid to call start(). The spec is silent on
// what happens if we call stop() afterwards, so don't call it.
shouldNotThrow("source = context.createBufferSource()");
shouldNotThrow("source.start()");
buffer = context.createBuffer(1,1, context.sampleRate);
shouldNotThrow("source = context.createBufferSource()");
shouldNotThrow("source.buffer = buffer");
shouldThrow("source.stop()");
buffer = context.createBuffer(1,1, context.sampleRate);
shouldNotThrow("source = context.createBufferSource()");
shouldNotThrow("source.buffer = buffer");
shouldNotThrow("source.start()");
shouldThrow("source.start()");
buffer = context.createBuffer(1,1, context.sampleRate);
shouldNotThrow("source = context.createBufferSource()");
shouldNotThrow("source.buffer = buffer");
shouldNotThrow("source.start()");
shouldNotThrow("source.stop()");
// Start/stop for OscillatorNodes
shouldNotThrow("source = context.createOscillator()");
shouldThrow("source.start(-Number.MIN_VALUE)");
shouldThrow("source.start(Infinity)");
shouldThrow("source.start(-Infinity)");
shouldThrow("source.start(NaN)");
shouldNotThrow("source.start()");
shouldThrow("source.stop(-Number.MIN_VALUE)");
shouldThrow("source.stop(Infinity)");
shouldThrow("source.stop(-Infinity)");
shouldThrow("source.stop(NaN)");
shouldNotThrow("source.stop()");
shouldNotThrow("osc = context.createOscillator()");
shouldThrow("osc.stop()");
shouldNotThrow("osc1 = context.createOscillator()");
shouldNotThrow("osc1.start()");
shouldNotThrow("osc1.stop()");
shouldThrow("osc.setPeriodicWave(null)");
// exponentialRampToValue should throw only for "zero" target values.
node = context.createGain();
node.connect(context.destination);
shouldNotThrow("node.gain.exponentialRampToValueAtTime(-1, 0.1)");
shouldThrow("node.gain.exponentialRampToValueAtTime(0, 0.1)");
// 1e-100 is 0 when converted to a single precision float.
shouldThrow("node.gain.exponentialRampToValueAtTime(1e-100, 0.1)");
// See crbug.com/459391.
// Math.pow(2, -149) = 1.401298464324817e-45 is the double-float value of the
// least positive single float number. We do it this way to make sure no round-off or conversion
// errors happen when reading 1.401298464324817e-45.
shouldNotThrow("node.gain.exponentialRampToValueAtTime(Math.pow(2, -149), 0.1)");
// Math.pow(2, -150) = 7.006492321624085d-46 is the largest double float value such that
// conversion to a float produces 0. Any larger value would produce a non-zero value when
// converted to a single float.
shouldThrow("node.gain.exponentialRampToValueAtTime(Math.pow(2, -150), 0.1)");
// Convolver buffer rate must match context rate. Create on offline context so we
// specify the context rate exactly, in case the test is run on platforms with different
// HW sample rates.
shouldNotThrow("oc = new OfflineAudioContext(1, 44100, 44100)");
shouldNotThrow("conv = oc.createConvolver()");
shouldThrow("conv.buffer = {}");
shouldThrow("conv.buffer = oc.createBuffer(1, 100, 22050)");
// conv.buffer should be unchanged (null) because the above failed.
shouldBeNull("conv.buffer");
// PannerNode channel count and mode
panner = context.createPanner();
// Channel count can only be set to 1 or 2.
shouldNotThrow("panner.channelCount = 1");
shouldNotThrow("panner.channelCount = 2");
shouldThrowAndBeUnchanged("panner.channelCount", "0");
shouldThrowAndBeUnchanged("panner.channelCount", "3");
// It is illegal to set the mode to 'max'
shouldThrowAndBeUnchanged("panner.channelCountMode", "'max'");
shouldNotThrow("panner.channelCountMode = 'explicit'");
shouldNotThrow("panner.channelCountMode = 'clamped-max'");
shouldNotThrow("panner.channelCountMode = 'junk'");
// Test channel count and mode for a ScriptProcessor.
shouldNotThrow("script = context.createScriptProcessor(256, 3)");
// Make sure the channelCount and mode are set correctly.
shouldBeEqualToNumber("script.channelCount", 3);
shouldBeEqualToString("script.channelCountMode", "explicit");
// Cannot change the channelCount or mode to anything else
shouldNotThrow("script.channelCount = 3");
shouldThrowAndBeUnchanged("script.channelCount", "1");
shouldThrowAndBeUnchanged("script.channelCount", "7");
shouldNotThrow("script.channelCountMode = 'explicit'");
shouldThrowAndBeUnchanged("script.channelCountMode", "'max'");
shouldThrowAndBeUnchanged("script.channelCountMode", "'clamped-max'");
shouldNotThrow("script.channelCountMode = 'junk'");
// noteOn and noteOff don't exist anymore
shouldBeUndefined("osc.noteOn");
shouldBeUndefined("osc.noteOff");
shouldBeUndefined("source.noteOn");
shouldBeUndefined("source.noteOff");
}
runTest();
successfullyParsed = true;
</script>
</body>
</html>