OLD | NEW |
1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
2 <html> | 2 <html> |
3 | 3 <head> |
4 <head> | 4 <title> |
5 <script src="../../resources/testharness.js"></script> | 5 audionode-connect-method-chaining.html |
6 <script src="../../resources/testharnessreport.js"></script> | 6 </title> |
7 <script src="../resources/audit-util.js"></script> | 7 <script src="../../resources/testharness.js"></script> |
8 <script src="../resources/audit.js"></script> | 8 <script src="../../resources/testharnessreport.js"></script> |
9 </head> | 9 <script src="../resources/audit-util.js"></script> |
10 | 10 <script src="../resources/audit.js"></script> |
11 <body> | 11 </head> |
12 <script> | 12 <body> |
13 | 13 <script id="layout-test-code"> |
14 // AudioNode dictionary with associated arguments. | 14 // AudioNode dictionary with associated arguments. |
15 var nodeDictionary = [ | 15 let nodeDictionary = [ |
16 { name: 'Analyser' }, | 16 {name: 'Analyser'}, {name: 'BiquadFilter'}, {name: 'BufferSource'}, |
17 { name: 'BiquadFilter' }, | 17 {name: 'ChannelMerger', args: [6]}, |
18 { name: 'BufferSource' }, | 18 {name: 'ChannelSplitter', args: [6]}, {name: 'Convolver'}, |
19 { name: 'ChannelMerger', args: [6] }, | 19 {name: 'Delay', args: []}, {name: 'DynamicsCompressor'}, {name: 'Gain'}, |
20 { name: 'ChannelSplitter', args: [6] }, | 20 {name: 'Oscillator'}, {name: 'Panner'}, |
21 { name: 'Convolver' }, | 21 {name: 'ScriptProcessor', args: [512, 1, 1]}, {name: 'StereoPanner'}, |
22 { name: 'Delay', args: [] }, | 22 {name: 'WaveShaper'} |
23 { name: 'DynamicsCompressor' }, | 23 ]; |
24 { name: 'Gain' }, | |
25 { name: 'Oscillator' }, | |
26 { name: 'Panner' }, | |
27 { name: 'ScriptProcessor', args: [512, 1, 1] }, | |
28 { name: 'StereoPanner' }, | |
29 { name: 'WaveShaper' } | |
30 ]; | |
31 | 24 |
32 | 25 |
33 function verifyReturnedNode(should, config) { | 26 function verifyReturnedNode(should, config) { |
34 should(config.destination === config.returned, | 27 should( |
35 'The return value of ' + config.desc + | 28 config.destination === config.returned, |
36 ' matches the destination ' + | 29 'The return value of ' + config.desc + ' matches the destination ' + |
37 config.returned.constructor.name) | 30 config.returned.constructor.name) |
38 .beEqualTo(true); | 31 .beEqualTo(true); |
39 } | 32 } |
40 | 33 |
41 // Test utility for batch method checking: in order to test 3 method | 34 // Test utility for batch method checking: in order to test 3 method |
42 // signatures, so we create 3 dummy destinations. | 35 // signatures, so we create 3 dummy destinations. |
43 // 1) .connect(GainNode) | 36 // 1) .connect(GainNode) |
44 // 2) .connect(BiquadFilterNode, output) | 37 // 2) .connect(BiquadFilterNode, output) |
45 // 3) .connect(ChannelMergerNode, output, input) | 38 // 3) .connect(ChannelMergerNode, output, input) |
46 function testConnectMethod(context, should, options) { | 39 function testConnectMethod(context, should, options) { |
47 var source = context['create' + options.name].apply(context, options.args)
; | 40 let source = |
48 var sourceName = source.constructor.name; | 41 context['create' + options.name].apply(context, options.args); |
| 42 let sourceName = source.constructor.name; |
49 | 43 |
50 var destination1 = context.createGain(); | 44 let destination1 = context.createGain(); |
51 verifyReturnedNode(should, { | 45 verifyReturnedNode(should, { |
52 source: source, | 46 source: source, |
53 destination: destination1, | 47 destination: destination1, |
54 returned: source.connect(destination1), | 48 returned: source.connect(destination1), |
55 desc: sourceName + '.connect(' + destination1.constructor.name + ')' | 49 desc: sourceName + '.connect(' + destination1.constructor.name + ')' |
| 50 }); |
| 51 |
| 52 let destination2 = context.createBiquadFilter(); |
| 53 verifyReturnedNode(should, { |
| 54 source: source, |
| 55 destination: destination2, |
| 56 returned: source.connect(destination2, 0), |
| 57 desc: |
| 58 sourceName + '.connect(' + destination2.constructor.name + ', 0)' |
| 59 }); |
| 60 |
| 61 let destination3 = context.createChannelMerger(); |
| 62 verifyReturnedNode(should, { |
| 63 source: source, |
| 64 destination: destination3, |
| 65 returned: source.connect(destination3, 0, 1), |
| 66 desc: sourceName + '.connect(' + destination3.constructor.name + |
| 67 ', 0, 1)' |
| 68 }); |
| 69 } |
| 70 |
| 71 |
| 72 let audit = Audit.createTaskRunner(); |
| 73 |
| 74 // Task: testing entries from the dictionary. |
| 75 audit.define('from-dictionary', (task, should) => { |
| 76 let context = new AudioContext(); |
| 77 |
| 78 for (let i = 0; i < nodeDictionary.length; i++) |
| 79 testConnectMethod(context, should, nodeDictionary[i]); |
| 80 |
| 81 task.done(); |
56 }); | 82 }); |
57 | 83 |
58 var destination2 = context.createBiquadFilter(); | 84 // Task: testing Media* nodes. |
59 verifyReturnedNode(should, { | 85 audit.define('media-group', (task, should) => { |
60 source: source, | 86 let context = new AudioContext(); |
61 destination: destination2, | 87 |
62 returned: source.connect(destination2, 0), | 88 // Test MediaElementSourceNode needs an <audio> element. |
63 desc: sourceName + '.connect(' + destination2.constructor.name + ', 0)' | 89 let mediaElement = document.createElement('audio'); |
| 90 testConnectMethod( |
| 91 context, should, |
| 92 {name: 'MediaElementSource', args: [mediaElement]}); |
| 93 |
| 94 testConnectMethod(context, should, {name: 'MediaStreamDestination'}); |
| 95 |
| 96 // MediaStreamSourceNode requires 'stream' object to be constructed, |
| 97 // which is a part of MediaStreamDestinationNode. |
| 98 let streamDestination = context.createMediaStreamDestination(); |
| 99 let stream = streamDestination.stream; |
| 100 testConnectMethod( |
| 101 context, should, {name: 'MediaStreamSource', args: [stream]}); |
| 102 |
| 103 task.done(); |
64 }); | 104 }); |
65 | 105 |
66 var destination3 = context.createChannelMerger(); | 106 // Task: test the exception thrown by invalid operation. |
67 verifyReturnedNode(should, { | 107 audit.define('invalid-operation', (task, should) => { |
68 source: source, | 108 let contextA = new AudioContext(); |
69 destination: destination3, | 109 let contextB = new AudioContext(); |
70 returned: source.connect(destination3, 0, 1), | 110 let gain1 = contextA.createGain(); |
71 desc: sourceName + '.connect(' + destination3.constructor.name + ', 0, 1
)' | 111 let gain2 = contextA.createGain(); |
| 112 |
| 113 // Test if the first connection throws correctly. The first gain node |
| 114 // does not have the second output, so it should throw. |
| 115 should(function() { |
| 116 gain1.connect(gain2, 1).connect(contextA.destination); |
| 117 }, 'Connecting with an invalid output').throw('IndexSizeError'); |
| 118 |
| 119 // Test if the second connection throws correctly. The contextB's |
| 120 // destination is not compatible with the nodes from contextA, thus the |
| 121 // first connection succeeds but the second one should throw. |
| 122 should( |
| 123 function() { |
| 124 gain1.connect(gain2).connect(contextB.destination); |
| 125 }, |
| 126 'Connecting to a node from the different context') |
| 127 .throw('InvalidAccessError'); |
| 128 |
| 129 task.done(); |
72 }); | 130 }); |
73 } | |
74 | 131 |
| 132 // Task: verify if the method chaining actually works. |
| 133 audit.define('verification', (task, should) => { |
| 134 // We pick the lowest sample rate allowed to run the test efficiently. |
| 135 let context = new OfflineAudioContext(1, 128, 3000); |
75 | 136 |
76 var audit = Audit.createTaskRunner(); | 137 let constantBuffer = createConstantBuffer(context, 1, 1.0); |
77 | 138 |
78 // Task: testing entries from the dictionary. | 139 let source = context.createBufferSource(); |
79 audit.define('from-dictionary', (task, should) => { | 140 source.buffer = constantBuffer; |
80 var context = new AudioContext(); | 141 source.loop = true; |
81 | 142 |
82 for (var i = 0; i < nodeDictionary.length; i++) | 143 let gain1 = context.createGain(); |
83 testConnectMethod(context, should, nodeDictionary[i]); | 144 gain1.gain.value = 0.5; |
| 145 let gain2 = context.createGain(); |
| 146 gain2.gain.value = 0.25; |
84 | 147 |
85 task.done(); | 148 source.connect(gain1).connect(gain2).connect(context.destination); |
86 }); | 149 source.start(); |
87 | 150 |
88 // Task: testing Media* nodes. | 151 context.startRendering() |
89 audit.define('media-group', (task, should) => { | 152 .then(function(buffer) { |
90 var context = new AudioContext(); | 153 should( |
| 154 buffer.getChannelData(0), |
| 155 'The output of chained connection of gain nodes') |
| 156 .beConstantValueOf(0.125); |
| 157 }) |
| 158 .then(() => task.done()); |
| 159 }); |
91 | 160 |
92 // Test MediaElementSourceNode needs an <audio> element. | 161 audit.run(); |
93 var mediaElement = document.createElement('audio'); | 162 </script> |
94 testConnectMethod(context, should, { name: 'MediaElementSource', args: [me
diaElement] }); | 163 </body> |
95 | |
96 testConnectMethod(context, should, { name: 'MediaStreamDestination' }); | |
97 | |
98 // MediaStreamSourceNode requires 'stream' object to be constructed, which | |
99 // is a part of MediaStreamDestinationNode. | |
100 var streamDestination = context.createMediaStreamDestination(); | |
101 var stream = streamDestination.stream; | |
102 testConnectMethod(context, should, { name: 'MediaStreamSource', args: [str
eam] }); | |
103 | |
104 task.done(); | |
105 }); | |
106 | |
107 // Task: test the exception thrown by invalid operation. | |
108 audit.define('invalid-operation', (task, should) => { | |
109 var contextA = new AudioContext(); | |
110 var contextB = new AudioContext(); | |
111 var gain1 = contextA.createGain(); | |
112 var gain2 = contextA.createGain(); | |
113 | |
114 // Test if the first connection throws correctly. The first gain node does | |
115 // not have the second output, so it should throw. | |
116 should(function () { | |
117 gain1.connect(gain2, 1).connect(contextA.destination); | |
118 }, 'Connecting with an invalid output').throw('IndexSizeError'); | |
119 | |
120 // Test if the second connection throws correctly. The contextB's | |
121 // destination is not compatible with the nodes from contextA, thus the | |
122 // first connection succeeds but the second one should throw. | |
123 should(function () { | |
124 gain1.connect(gain2).connect(contextB.destination); | |
125 }, 'Connecting to a node from the different context').throw('InvalidAccess
Error'); | |
126 | |
127 task.done(); | |
128 }); | |
129 | |
130 // Task: verify if the method chaining actually works. | |
131 audit.define('verification', (task, should) => { | |
132 // We pick the lowest sample rate allowed to run the test efficiently. | |
133 var context = new OfflineAudioContext(1, 128, 3000); | |
134 | |
135 var constantBuffer = createConstantBuffer(context, 1, 1.0); | |
136 | |
137 var source = context.createBufferSource(); | |
138 source.buffer = constantBuffer; | |
139 source.loop = true; | |
140 | |
141 var gain1 = context.createGain(); | |
142 gain1.gain.value = 0.5; | |
143 var gain2 = context.createGain(); | |
144 gain2.gain.value = 0.25; | |
145 | |
146 source.connect(gain1).connect(gain2).connect(context.destination); | |
147 source.start(); | |
148 | |
149 context.startRendering().then(function (buffer) { | |
150 should(buffer.getChannelData(0), 'The output of chained connection of ga
in nodes') | |
151 .beConstantValueOf(0.125); | |
152 }).then(() => task.done()); | |
153 }); | |
154 | |
155 audit.run(); | |
156 </script> | |
157 </body> | |
158 | |
159 </html> | 164 </html> |
OLD | NEW |