| <!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 method chaining feature of AudioNode.connect() method.'); |
| window.jsTestIsAsync = true; |
| |
| // AudioNode dictionary with associated arguments. |
| var nodeDictionary = [ |
| { name: 'Analyser' }, |
| { name: 'BiquadFilter' }, |
| { name: 'BufferSource' }, |
| { name: 'ChannelMerger', args: [6] }, |
| { name: 'ChannelSplitter', args: [6] }, |
| { name: 'Convolver' }, |
| { name: 'Delay', args: [] }, |
| { name: 'DynamicsCompressor' }, |
| { name: 'Gain' }, |
| { name: 'Oscillator' }, |
| { name: 'Panner' }, |
| { name: 'ScriptProcessor', args: [512, 1, 1] }, |
| { name: 'StereoPanner' }, |
| { name: 'WaveShaper' } |
| ]; |
| |
| |
| function verifyReturnedNode(config) { |
| if (config.destination === config.returned) { |
| testPassed('The return value of ' + config.desc + ' matches the destination ' + |
| config.returned.constructor.name + '.'); |
| } else { |
| testFailed('The return value of ' + config.desc + ' does NOT match the destination ' + |
| config.destination.constructor.name + '.'); |
| } |
| } |
| |
| // Test utility for batch method checking: in order to test 3 method |
| // signatures, so we create 3 dummy destinations. |
| // 1) .connect(GainNode) |
| // 2) .connect(BiquadFilterNode, output) |
| // 3) .connect(ChannelMergerNode, output, input) |
| function testConnectMethod(context, options) { |
| var source = context['create' + options.name].apply(context, options.args); |
| var sourceName = source.constructor.name; |
| |
| var destination1 = context.createGain(); |
| verifyReturnedNode({ |
| source: source, |
| destination: destination1, |
| returned: source.connect(destination1), |
| desc: sourceName + '.connect(' + destination1.constructor.name + ')' |
| }); |
| |
| var destination2 = context.createBiquadFilter(); |
| verifyReturnedNode({ |
| source: source, |
| destination: destination2, |
| returned: source.connect(destination2, 0), |
| desc: sourceName + '.connect(' + destination2.constructor.name + ', 0)' |
| }); |
| |
| var destination3 = context.createChannelMerger(); |
| verifyReturnedNode({ |
| source: source, |
| destination: destination3, |
| returned: source.connect(destination3, 0, 1), |
| desc: sourceName + '.connect(' + destination3.constructor.name + ', 0, 1)' |
| }); |
| } |
| |
| |
| var audit = Audit.createTaskRunner(); |
| |
| // Task: testing entries from the dictionary. |
| audit.defineTask('from-dictionary', function (done) { |
| var context = new AudioContext(); |
| |
| for (var i = 0; i < nodeDictionary.length; i++) |
| testConnectMethod(context, nodeDictionary[i]); |
| |
| done(); |
| }); |
| |
| // Task: testing Media* nodes. |
| audit.defineTask('media-group', function (done) { |
| var context = new AudioContext(); |
| |
| // Test MediaElementSourceNode needs an <audio> element. |
| var mediaElement = document.createElement('audio'); |
| testConnectMethod(context, { name: 'MediaElementSource', args: [mediaElement] }); |
| |
| testConnectMethod(context, { name: 'MediaStreamDestination' }); |
| |
| // MediaStreamSourceNode requires 'stream' object to be constructed, which |
| // is a part of MediaStreamDestinationNode. |
| var streamDestination = context.createMediaStreamDestination(); |
| var stream = streamDestination.stream; |
| testConnectMethod(context, { name: 'MediaStreamSource', args: [stream] }); |
| |
| done(); |
| }); |
| |
| // Task: test the exception thrown by invalid operation. |
| audit.defineTask('invalid-operation', function (done) { |
| var contextA = new AudioContext(); |
| var contextB = new AudioContext(); |
| var gain1 = contextA.createGain(); |
| var gain2 = contextA.createGain(); |
| |
| // Test if the first connection throws correctly. The first gain node does |
| // not have the second output, so it should throw. |
| Should('Connecting with an invalid output', function () { |
| gain1.connect(gain2, 1).connect(contextA.destination); |
| }).throw('IndexSizeError'); |
| |
| // Test if the second connection throws correctly. The contextB's |
| // destination is not compatible with the nodes from contextA, thus the |
| // first connection succeeds but the second one should throw. |
| Should('Connecting to a node from the different context', function () { |
| gain1.connect(gain2).connect(contextB.destination); |
| }).throw('SyntaxError'); |
| |
| done(); |
| }); |
| |
| // Task: verify if the method chaining actually works. |
| audit.defineTask('verification', function (done) { |
| // We pick the lowest sample rate allowed to run the test efficiently. |
| var context = new OfflineAudioContext(1, 128, 3000); |
| |
| var constantBuffer = createConstantBuffer(context, 1, 1.0); |
| |
| var source = context.createBufferSource(); |
| source.buffer = constantBuffer; |
| source.loop = true; |
| |
| var gain1 = context.createGain(); |
| gain1.gain.value = 0.5; |
| var gain2 = context.createGain(); |
| gain2.gain.value = 0.25; |
| |
| source.connect(gain1).connect(gain2).connect(context.destination); |
| source.start(); |
| |
| context.startRendering().then(function (buffer) { |
| Should('The output of chained connection of gain nodes', buffer.getChannelData(0)) |
| .beConstantValueOf(0.125); |
| }).then(done); |
| }); |
| |
| audit.defineTask('finish', function (done) { |
| finishJSTest(); |
| done(); |
| }); |
| |
| audit.runTasks( |
| 'from-dictionary', |
| 'media-group', |
| 'invalid-operation', |
| 'verification', |
| 'finish' |
| ); |
| |
| successfullyParsed = true; |
| </script> |
| </body> |
| |
| </html> |