| <!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 ArrayBuffer (unspecified error) |
| shouldThrow("context.decodeAudioData(null, function() {}, function () {})"); |
| // 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)"); |
| // Real array is too long. |
| shouldThrow("context.createPeriodicWave(new Float32Array(4100), new Float32Array(4100))"); |
| // Imaginary array is too long. |
| shouldThrow("context.createPeriodicWave(new Float32Array(100), new Float32Array(4100))"); |
| // Real and imaginary arrays must have the same size: IndexSizeError |
| shouldThrow("context.createPeriodicWave(new Float32Array(10), new Float32Array(7))"); |
| // Check upper limit is correct. |
| shouldNotThrow("context.createPeriodicWave(new Float32Array(2048), new Float32Array(2048))"); |
| shouldThrow("context.createPeriodicWave(new Float32Array(2049), new Float32Array(2049))"); |
| |
| |
| // 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"); |
| |
| // 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."); |
| } |
| |
| // 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 = 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"); |
| // Setting the buffer twice will eventually throw an error, but for now, it's just a deprecation |
| // warning. |
| shouldNotThrow("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()"); |
| |
| // exponentialRampToValue should throw on non-positive target values. |
| node = context.createGain(); |
| node.connect(context.destination); |
| shouldThrow("node.gain.exponentialRampToValueAtTime(-1, 0.1)"); |
| shouldThrow("node.gain.exponentialRampToValueAtTime(0, 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 = 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> |