tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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>