OLD | NEW |
1 <!doctype html> | 1 <!DOCTYPE html> |
2 <html> | 2 <html> |
3 <head> | 3 <head> |
4 <script src="../../resources/testharness.js"></script> | 4 <title> |
5 <script src="../../resources/testharnessreport.js"></script> | 5 Test decodeAudioData promises |
6 <script src="../resources/audit.js"></script> | 6 </title> |
7 <title>Test decodeAudioData promises</title> | 7 <script src="../../resources/testharness.js"></script> |
8 </head> | 8 <script src="../../resources/testharnessreport.js"></script> |
9 <body> | 9 <script src="../resources/audit.js"></script> |
10 <script> | 10 </head> |
11 // The functionality of decodeAudioData() is orthogonal to the type and the | 11 <body> |
12 // state of AudioContext. So we use the online context here and any | 12 <script id="layout-test-code"> |
13 // resampling of the file is okay for this test. | 13 // The functionality of decodeAudioData() is orthogonal to the type and |
14 let context = new AudioContext(); | 14 // the state of AudioContext. So we use the online context here and any |
| 15 // resampling of the file is okay for this test. |
| 16 let context = new AudioContext(); |
15 | 17 |
16 // Test file URLs. | 18 // Test file URLs. |
17 let validAudioFileUrl = '../resources/media/24bit-44khz.wav'; | 19 let validAudioFileUrl = '../resources/media/24bit-44khz.wav'; |
18 let invalidAudioFileUrl = '../resources/media/invalid-audio-file.txt'; | 20 let invalidAudioFileUrl = '../resources/media/invalid-audio-file.txt'; |
19 | 21 |
20 // Global storage for array buffers from XHR. | 22 // Global storage for array buffers from XHR. |
21 let validArrayBuffer; | 23 let validArrayBuffer; |
22 let invalidArrayBuffer; | 24 let invalidArrayBuffer; |
23 | 25 |
24 // Decoded data from validAudioFile. | 26 // Decoded data from validAudioFile. |
25 let referenceDecodedAudioBuffer; | 27 let referenceDecodedAudioBuffer; |
26 | 28 |
27 let audit = Audit.createTaskRunner(); | 29 let audit = Audit.createTaskRunner(); |
28 | 30 |
29 // Preload ArrayBuffer and the reference AudioBuffer from URLs. | 31 // Preload ArrayBuffer and the reference AudioBuffer from URLs. |
30 audit.define('preload-arraybuffer', (task, should) => { | 32 audit.define('preload-arraybuffer', (task, should) => { |
31 Promise | 33 Promise |
32 .all([ | 34 .all([ |
33 should(Audit.loadFileFromUrl(validAudioFileUrl), | 35 should( |
34 "Loading valid audio file") | 36 Audit.loadFileFromUrl(validAudioFileUrl), |
35 .beResolved(), | 37 'Loading valid audio file') |
36 should(Audit.loadFileFromUrl(invalidAudioFileUrl), | 38 .beResolved(), |
37 "loading invalid audio file") | 39 should( |
38 .beResolved() | 40 Audit.loadFileFromUrl(invalidAudioFileUrl), |
39 ]) | 41 'loading invalid audio file') |
40 .then((arrayBuffers) => { | 42 .beResolved() |
41 validArrayBuffer = arrayBuffers[0]; | 43 ]) |
42 invalidArrayBuffer = arrayBuffers[1]; | 44 .then((arrayBuffers) => { |
43 }) | 45 validArrayBuffer = arrayBuffers[0]; |
44 .then(() => task.done()); | 46 invalidArrayBuffer = arrayBuffers[1]; |
45 }); | 47 }) |
| 48 .then(() => task.done()); |
| 49 }); |
46 | 50 |
47 // Decode a valid encoded file and verify that the promise succeeds | 51 // Decode a valid encoded file and verify that the promise succeeds |
48 // correctly. | 52 // correctly. |
49 audit.define('decode-valid-file', (task, should) => { | 53 audit.define('decode-valid-file', (task, should) => { |
50 // Note that the order of completion for each promise is undefined and | 54 // Note that the order of completion for each promise is undefined and |
51 // we do not care about it in this test. | 55 // we do not care about it in this test. |
52 Promise | 56 Promise |
53 .all([ | 57 .all([ |
54 // Do not use the original arrayBuffers for decoding; decode a copy | 58 // Do not use the original arrayBuffers for decoding; decode a |
55 // because decodeAudioData will detach the buffers. | 59 // copy because decodeAudioData will detach the buffers. |
56 should(context.decodeAudioData(validArrayBuffer.slice(0)), | 60 should( |
57 'Decoding a valid audio file') | 61 context.decodeAudioData(validArrayBuffer.slice(0)), |
58 .beResolved() | 62 'Decoding a valid audio file') |
59 .then(buffer => referenceDecodedAudioBuffer = buffer), | 63 .beResolved() |
60 should(context.decodeAudioData(invalidArrayBuffer.slice(0)), | 64 .then(buffer => referenceDecodedAudioBuffer = buffer), |
61 'Decoding an invalid audio file') | 65 should( |
62 .beRejectedWith('EncodingError'), | 66 context.decodeAudioData(invalidArrayBuffer.slice(0)), |
63 should(context.decodeAudioData(null), 'Decoding null AudioBuffer') | 67 'Decoding an invalid audio file') |
64 .beRejected() | 68 .beRejectedWith('EncodingError'), |
65 ]) | 69 should(context.decodeAudioData(null), 'Decoding null AudioBuffer') |
66 .then(() => task.done()); | 70 .beRejected() |
67 }); | 71 ]) |
| 72 .then(() => task.done()); |
| 73 }); |
68 | 74 |
69 // Decode a valid file and verify that the promise is fulfilled and the | 75 // Decode a valid file and verify that the promise is fulfilled and the |
70 // successCallback is invoked and both have identical decoded audio buffers. | 76 // successCallback is invoked and both have identical decoded audio |
71 audit.define("promise-and-success-callback", (task, should) => { | 77 // buffers. |
72 let bufferByCallback; | 78 audit.define('promise-and-success-callback', (task, should) => { |
73 let bufferByPromise; | 79 let bufferByCallback; |
| 80 let bufferByPromise; |
74 | 81 |
75 // Use one callback for success and error. |callbackArg| is a parameter | 82 // Use one callback for success and error. |callbackArg| is a parameter |
76 // for callback functions; it is a decoded audio buffer for success case | 83 // for callback functions; it is a decoded audio buffer for success case |
77 // and an error object for failure case. | 84 // and an error object for failure case. |
78 let successOrErrorCallback = (callbackArg) => { | 85 let successOrErrorCallback = (callbackArg) => { |
79 should(callbackArg instanceof AudioBuffer, | 86 should( |
80 'Decoding valid file by callback function') | 87 callbackArg instanceof AudioBuffer, |
81 .message('successCallback invoked correctly', | 88 'Decoding valid file by callback function') |
82 'errorCallback incorrectly invoked with ' + callbackArg); | 89 .message( |
83 bufferByCallback = callbackArg; | 90 'successCallback invoked correctly', |
84 }; | 91 'errorCallback incorrectly invoked with ' + callbackArg); |
| 92 bufferByCallback = callbackArg; |
| 93 }; |
85 | 94 |
86 // Step 1: Decode a file with callback functions. | 95 // Step 1: Decode a file with callback functions. |
87 let step1 = context.decodeAudioData(validArrayBuffer.slice(), | 96 let step1 = context.decodeAudioData( |
88 successOrErrorCallback, | 97 validArrayBuffer.slice(), successOrErrorCallback, |
89 successOrErrorCallback); | 98 successOrErrorCallback); |
90 | 99 |
91 // Step 2: Then decode a file with promise pattern. | 100 // Step 2: Then decode a file with promise pattern. |
92 let step2 = should(step1, 'Decoding a file via promise') | 101 let step2 = should(step1, 'Decoding a file via promise') |
93 .beResolved() | 102 .beResolved() |
94 .then((audioBuffer) => { | 103 .then((audioBuffer) => { |
95 bufferByPromise = audioBuffer; | 104 bufferByPromise = audioBuffer; |
96 }); | 105 }); |
97 | 106 |
98 // Step 3: compare two buffers from Step 1 and Step 2. | 107 // Step 3: compare two buffers from Step 1 and Step 2. |
99 step2.then(() => { | 108 step2.then(() => { |
100 should(bufferByCallback === bufferByPromise, | 109 should( |
101 'Two buffers decoded by callback function and promise') | 110 bufferByCallback === bufferByPromise, |
102 .message('are identical', 'are different'); | 111 'Two buffers decoded by callback function and promise') |
103 task.done(); | 112 .message('are identical', 'are different'); |
| 113 task.done(); |
| 114 }); |
104 }); | 115 }); |
105 }); | |
106 | 116 |
107 // Decode an invalid file and verify that the promise is rejected and the | 117 // Decode an invalid file and verify that the promise is rejected and the |
108 // errorCallback is invoked. | 118 // errorCallback is invoked. |
109 audit.define("promise-and-error-callback", (task, should) => { | 119 audit.define('promise-and-error-callback', (task, should) => { |
110 let successOrErrorCallback = (callbackArg) => { | 120 let successOrErrorCallback = (callbackArg) => { |
111 should(callbackArg instanceof Error, | 121 should( |
112 'Decoding invalid file with promise and callback:') | 122 callbackArg instanceof Error, |
113 .message('errorCallback invoked correctly with ' + callbackArg, | 123 'Decoding invalid file with promise and callback:') |
114 'successCallback should not have invoked'); | 124 .message( |
115 }; | 125 'errorCallback invoked correctly with ' + callbackArg, |
| 126 'successCallback should not have invoked'); |
| 127 }; |
116 | 128 |
117 let decodeAudioDataPromise = | 129 let decodeAudioDataPromise = context.decodeAudioData( |
118 context.decodeAudioData(invalidArrayBuffer.slice(), | 130 invalidArrayBuffer.slice(), successOrErrorCallback, |
119 successOrErrorCallback, | 131 successOrErrorCallback); |
120 successOrErrorCallback); | |
121 | 132 |
122 should(decodeAudioDataPromise, 'decodeAudioData promise') | 133 should(decodeAudioDataPromise, 'decodeAudioData promise') |
123 .beRejected('EncodingError') | 134 .beRejected('EncodingError') |
124 .then(() => task.done()); | 135 .then(() => task.done()); |
125 }); | 136 }); |
126 | 137 |
127 // decodeAudioData() should be functional even after the associated context | 138 // decodeAudioData() should be functional even after the associated |
128 // is closed. | 139 // context is closed. |
129 audit.define('decoding-on-closed-context', (task, should) => { | 140 audit.define('decoding-on-closed-context', (task, should) => { |
130 // Use one handler for resolve and reject. |promiseArg| is a parameter for | 141 // Use one handler for resolve and reject. |promiseArg| is a parameter |
131 // handlers; it is a decoded audio buffer for success case and an error | 142 // for handlers; it is a decoded audio buffer for success case and an |
132 // object for failure case. | 143 // error object for failure case. |
133 let resolveOrReject = (promiseArg) => { | 144 let resolveOrReject = (promiseArg) => { |
134 let didDecode = promiseArg instanceof AudioBuffer; | 145 let didDecode = promiseArg instanceof AudioBuffer; |
135 | 146 |
136 if (didDecode) { | 147 if (didDecode) { |
137 // Compare two decoded AudioBuffers. | 148 // Compare two decoded AudioBuffers. |
138 let actual = promiseArg; | 149 let actual = promiseArg; |
139 let expected = referenceDecodedAudioBuffer; | 150 let expected = referenceDecodedAudioBuffer; |
140 should(actual.length, 'Decoded buffer length (frames)') | 151 should(actual.length, 'Decoded buffer length (frames)') |
141 .beEqualTo(expected.length); | 152 .beEqualTo(expected.length); |
142 should(actual.duration, 'Decoded buffer duration (sec)') | 153 should(actual.duration, 'Decoded buffer duration (sec)') |
143 .beEqualTo(expected.duration); | 154 .beEqualTo(expected.duration); |
144 should(actual.sampleRate, 'Decoded buffer sample rate (Hz)') | 155 should(actual.sampleRate, 'Decoded buffer sample rate (Hz)') |
145 .beEqualTo(expected.sampleRate); | 156 .beEqualTo(expected.sampleRate); |
146 should(actual.numberOfChannels, | 157 should( |
147 'Number of channels in decoded buffer') | 158 actual.numberOfChannels, 'Number of channels in decoded buffer') |
148 .beEqualTo(expected.numberOfChannels); | 159 .beEqualTo(expected.numberOfChannels); |
149 for (let c = 0; c < expected.numberOfChannels; ++c) { | 160 for (let c = 0; c < expected.numberOfChannels; ++c) { |
150 let actualChannelData = actual.getChannelData(c); | 161 let actualChannelData = actual.getChannelData(c); |
151 let expectedChannelData = expected.getChannelData(c); | 162 let expectedChannelData = expected.getChannelData(c); |
152 should(actualChannelData, 'Decoded buffer channel #' + c) | 163 should(actualChannelData, 'Decoded buffer channel #' + c) |
153 .beEqualToArray(expectedChannelData, | 164 .beEqualToArray( |
154 'the expected channel #' + c); | 165 expectedChannelData, 'the expected channel #' + c); |
| 166 } |
| 167 should(task.state, 'The buffer') |
| 168 .message( |
| 169 'correctly decoded after the context has been closed', |
| 170 'decoding succeeded but the data is incorrect'); |
155 } | 171 } |
156 should(task.state, 'The buffer') | |
157 .message('correctly decoded after the context has been closed', | |
158 'decoding succeeded but the data is incorrect'); | |
159 } | |
160 | 172 |
161 should(didDecode, 'Decoding ArrayBuffer after context has been closed') | 173 should( |
162 .message('completed successfully', 'failed : ' + promiseArg); | 174 didDecode, 'Decoding ArrayBuffer after context has been closed') |
163 }; | 175 .message('completed successfully', 'failed : ' + promiseArg); |
| 176 }; |
164 | 177 |
165 let onlineContext = new AudioContext(); | 178 let onlineContext = new AudioContext(); |
166 onlineContext.close() | 179 onlineContext.close() |
167 .then(() => { return context.decodeAudioData(validArrayBuffer); }) | 180 .then(() => { |
168 .then(resolveOrReject, resolveOrReject) | 181 return context.decodeAudioData(validArrayBuffer); |
169 .then(() => { task.done(); }); | 182 }) |
170 }); | 183 .then(resolveOrReject, resolveOrReject) |
| 184 .then(() => { |
| 185 task.done(); |
| 186 }); |
| 187 }); |
171 | 188 |
172 audit.run(); | 189 audit.run(); |
173 </script> | 190 </script> |
174 </body> | 191 </body> |
175 </html> | 192 </html> |
OLD | NEW |