| 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 |