mediasource-errors.html (13626B)
1 <!DOCTYPE html> 2 <!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). --> 3 <meta charset="utf-8"> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 <script src="mediasource-util.js"></script> 7 <script> 8 function ErrorTest(testFunction, description) 9 { 10 mediasource_test(function(test, mediaElement, mediaSource) 11 { 12 var segmentInfo = MediaSourceUtil.SEGMENT_INFO; 13 14 if (!segmentInfo) { 15 assert_unreached("No segment info compatible with this MediaSource implementation."); 16 return; 17 } 18 19 var sourceBuffer = mediaSource.addSourceBuffer(segmentInfo.type); 20 MediaSourceUtil.loadBinaryData(test, segmentInfo.url, function(mediaData) 21 { 22 testFunction(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData); 23 }); 24 }, description); 25 } 26 27 ErrorTest(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData) 28 { 29 var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]); 30 31 test.expectEvent(sourceBuffer, "error", "sourceBuffer error."); 32 test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended."); 33 test.expectEvent(mediaElement, "error", "mediaElement error."); 34 test.expectEvent(mediaSource, "sourceended", "mediaSource ended."); 35 test.expectEvent(mediaSource, "sourceclose", "mediaSource closed."); 36 sourceBuffer.appendBuffer(mediaSegment); 37 38 test.waitForExpectedEvents(function() 39 { 40 assert_true(mediaElement.error != null); 41 assert_equals(mediaElement.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED); 42 43 assert_equals(mediaSource.sourceBuffers.length, 0); 44 assert_equals(mediaSource.readyState, "closed"); 45 test.done(); 46 }); 47 }, "Appending media segment before the first initialization segment."); 48 49 ErrorTest(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData) 50 { 51 assert_equals(mediaElement.readyState, HTMLMediaElement.HAVE_NOTHING); 52 53 // Fail if the append error algorithm occurs, since the decode 54 // error will be provided by us directly via endOfStream(). 55 sourceBuffer.addEventListener("error", test.unreached_func("'error' should not be fired on sourceBuffer")); 56 57 test.expectEvent(mediaElement, "error", "mediaElement error."); 58 test.expectEvent(mediaSource, "sourceended", "mediaSource ended."); 59 test.expectEvent(mediaSource, "sourceclose", "mediaSource closed."); 60 61 mediaSource.endOfStream("decode"); 62 63 test.waitForExpectedEvents(function() 64 { 65 assert_true(mediaElement.error != null); 66 assert_equals(mediaElement.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED); 67 68 assert_equals(mediaSource.sourceBuffers.length, 0); 69 assert_equals(mediaSource.readyState, "closed"); 70 71 // Give a short time for a broken implementation to errantly fire 72 // "error" on sourceBuffer. 73 test.step_timeout(test.step_func_done(), 0); 74 }); 75 }, "Signaling 'decode' error via endOfStream() before initialization segment has been appended."); 76 77 ErrorTest(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData) 78 { 79 assert_equals(mediaElement.readyState, HTMLMediaElement.HAVE_NOTHING); 80 81 // Fail if the append error algorithm occurs, since the network 82 // error will be provided by us directly via endOfStream(). 83 sourceBuffer.addEventListener("error", test.unreached_func("'error' should not be fired on sourceBuffer")); 84 85 test.expectEvent(mediaElement, "error", "mediaElement error."); 86 test.expectEvent(mediaSource, "sourceended", "mediaSource ended."); 87 test.expectEvent(mediaSource, "sourceclose", "mediaSource closed."); 88 89 mediaSource.endOfStream("network"); 90 91 test.waitForExpectedEvents(function() 92 { 93 assert_true(mediaElement.error != null); 94 assert_equals(mediaElement.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED); 95 96 assert_equals(mediaSource.sourceBuffers.length, 0); 97 assert_equals(mediaSource.readyState, "closed"); 98 99 // Give a short time for a broken implementation to errantly fire 100 // "error" on sourceBuffer. 101 test.step_timeout(test.step_func_done(), 0); 102 }); 103 }, "Signaling 'network' error via endOfStream() before initialization segment has been appended."); 104 105 ErrorTest(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData) 106 { 107 var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init); 108 assert_equals(mediaElement.readyState, HTMLMediaElement.HAVE_NOTHING); 109 110 // Fail if the append error algorithm occurs, since the decode 111 // error will be provided by us directly via endOfStream(). 112 sourceBuffer.addEventListener("error", test.unreached_func("'error' should not be fired on sourceBuffer")); 113 114 test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended."); 115 test.expectEvent(mediaElement, "loadedmetadata", "mediaElement metadata."); 116 sourceBuffer.appendBuffer(initSegment); 117 118 test.waitForExpectedEvents(function() 119 { 120 assert_equals(mediaElement.readyState, HTMLMediaElement.HAVE_METADATA); 121 122 test.expectEvent(mediaElement, "error", "mediaElement error."); 123 test.expectEvent(mediaSource, "sourceended", "mediaSource ended."); 124 mediaSource.endOfStream("decode"); 125 }); 126 127 test.waitForExpectedEvents(function() 128 { 129 assert_true(mediaElement.error != null); 130 assert_equals(mediaElement.error.code, MediaError.MEDIA_ERR_DECODE); 131 assert_equals(mediaSource.readyState, "ended"); 132 133 // Give a short time for a broken implementation to errantly fire 134 // "error" on sourceBuffer. 135 test.step_timeout(test.step_func_done(), 0); 136 }); 137 138 }, "Signaling 'decode' error via endOfStream() after initialization segment has been appended and the HTMLMediaElement has reached HAVE_METADATA."); 139 140 ErrorTest(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData) 141 { 142 var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init); 143 assert_equals(mediaElement.readyState, HTMLMediaElement.HAVE_NOTHING); 144 145 // Fail if the append error algorithm occurs, since the network 146 // error will be provided by us directly via endOfStream(). 147 sourceBuffer.addEventListener("error", test.unreached_func("'error' should not be fired on sourceBuffer")); 148 149 test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended."); 150 test.expectEvent(mediaElement, "loadedmetadata", "mediaElement metadata."); 151 sourceBuffer.appendBuffer(initSegment); 152 153 test.waitForExpectedEvents(function() 154 { 155 assert_equals(mediaElement.readyState, HTMLMediaElement.HAVE_METADATA); 156 test.expectEvent(mediaElement, "error", "mediaElement error."); 157 test.expectEvent(mediaSource, "sourceended", "mediaSource ended."); 158 mediaSource.endOfStream("network"); 159 }); 160 161 test.waitForExpectedEvents(function() 162 { 163 assert_true(mediaElement.error != null); 164 assert_equals(mediaElement.error.code, MediaError.MEDIA_ERR_NETWORK); 165 assert_equals(mediaSource.readyState, "ended"); 166 167 // Give a short time for a broken implementation to errantly fire 168 // "error" on sourceBuffer. 169 test.step_timeout(test.step_func_done(), 0); 170 }); 171 }, "Signaling 'network' error via endOfStream() after initialization segment has been appended and the HTMLMediaElement has reached HAVE_METADATA."); 172 173 ErrorTest(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData) 174 { 175 assert_equals(mediaElement.readyState, HTMLMediaElement.HAVE_NOTHING); 176 177 var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init); 178 test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended."); 179 test.expectEvent(mediaElement, "loadedmetadata", "mediaElement metadata."); 180 sourceBuffer.appendBuffer(initSegment); 181 182 test.waitForExpectedEvents(function() 183 { 184 assert_equals(mediaElement.readyState, HTMLMediaElement.HAVE_METADATA); 185 var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]); 186 var index = segmentInfo.init.size + (mediaSegment.length - 1) / 2; 187 // Corrupt the media data from index of mediaData, so it can signal 'decode' error. 188 // Here use mediaSegment to replace the original mediaData[index, index + mediaSegment.length] 189 mediaData.set(mediaSegment, index); 190 191 test.expectEvent(sourceBuffer, "error", "sourceBuffer error."); 192 test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended."); 193 test.expectEvent(mediaElement, "error", "mediaElement error."); 194 test.expectEvent(mediaSource, "sourceended", "mediaSource ended."); 195 sourceBuffer.appendBuffer(mediaData); 196 }); 197 198 test.waitForExpectedEvents(function() 199 { 200 assert_true(mediaElement.error != null); 201 assert_equals(mediaElement.error.code, MediaError.MEDIA_ERR_DECODE); 202 test.done(); 203 }); 204 }, "Signaling 'decode' error via segment parser loop algorithm after initialization segment has been appended."); 205 206 ErrorTest(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData) 207 { 208 assert_equals(mediaElement.readyState, HTMLMediaElement.HAVE_NOTHING); 209 210 var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]); 211 var index = segmentInfo.init.size + (mediaSegment.length - 1) / 2; 212 // Corrupt the media data from index of mediaData, so it can signal 'decode' error. 213 // Here use mediaSegment to replace the original mediaData[index, index + mediaSegment.length] 214 mediaData.set(mediaSegment, index); 215 216 // Depending on implementation, mediaElement transition to 217 // HAVE_METADATA and dispatching 'loadedmetadata' may occur, since the 218 // initialization segment is uncorrupted and forms the initial part of 219 // the appended bytes. The segment parser loop continues and 220 // eventually should observe decode error. Other implementations may 221 // delay such transition until some larger portion of the append's 222 // parsing is completed or until the media element is configured to 223 // handle the playback of media with the associated metadata (which may 224 // not occur in this case before the MSE append error algorithm executes.) 225 // So we cannot reliably expect the lack or presence of 226 // 'loadedmetadata' before the MSE append error algortihm executes in 227 // this case; similarly, mediaElement's resulting readyState may be 228 // either HAVE_NOTHING or HAVE_METADATA after the append error 229 // algorithm executes, and the resulting MediaError code would 230 // respectively be MEDIA_ERR_SRC_NOT_SUPPORTED or MEDIA_ERR_DECODE. 231 let loaded = false; 232 mediaElement.addEventListener("loadedmetadata", test.step_func(() => { loaded = true; })); 233 let errored = false; 234 mediaElement.addEventListener("error", test.step_func(() => { errored = true; })); 235 236 test.expectEvent(sourceBuffer, "error", "sourceBuffer error."); 237 test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended."); 238 test.expectEvent(mediaSource, "sourceended", "mediaSource ended."); 239 sourceBuffer.appendBuffer(mediaData); 240 241 let verifyFinalState = test.step_func(function() { 242 if (loaded) { 243 assert_greater_than(mediaElement.readyState, HTMLMediaElement.HAVE_NOTHING); 244 assert_true(mediaElement.error != null); 245 assert_equals(mediaElement.error.code, MediaError.MEDIA_ERR_DECODE); 246 test.done(); 247 } else { 248 assert_equals(mediaElement.readyState, HTMLMediaElement.HAVE_NOTHING); 249 assert_true(mediaElement.error != null); 250 assert_equals(mediaElement.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED); 251 test.done(); 252 } 253 }); 254 255 let awaitMediaElementError = test.step_func(function() { 256 if (!errored) { 257 test.step_timeout(awaitMediaElementError, 100); 258 } else { 259 verifyFinalState(); 260 } 261 }); 262 263 test.waitForExpectedEvents(function() 264 { 265 // Not all implementations will reliably fire a "loadedmetadata" 266 // event, so we use custom logic to verify mediaElement state based 267 // on whether or not "loadedmetadata" was ever fired. But first 268 // we must ensure "error" was fired on the mediaElement. 269 awaitMediaElementError(); 270 }); 271 272 }, "Signaling 'decode' error via segment parser loop algorithm of append containing init plus corrupted media segment."); 273 </script>