tor-browser

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

mediasource-duration.html (21303B)


      1 <!DOCTYPE html>
      2 <!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
      3 <html>
      4    <head>
      5        <title>MediaSource.duration &amp; HTMLMediaElement.duration test cases.</title>
      6        <script src="/resources/testharness.js"></script>
      7        <script src="/resources/testharnessreport.js"></script>
      8        <script src="mediasource-util.js"></script>
      9    </head>
     10    <body>
     11        <div id="log"></div>
     12        <script>
     13 
     14          var subType = MediaSourceUtil.getSubType(MediaSourceUtil.AUDIO_ONLY_TYPE);
     15          var manifestFilenameAudio = subType + "/test-a-128k-44100Hz-1ch-manifest.json";
     16          var manifestFilenameVideo = subType + "/test-v-128k-320x240-30fps-10kfr-manifest.json";
     17 
     18          function mediasource_truncated_duration_seek_test(testFunction, description, options)
     19          {
     20              return mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
     21              {
     22                  assert_greater_than(segmentInfo.duration, 2, 'Sufficient test media duration');
     23 
     24                  var fullDuration = segmentInfo.duration;
     25                  var seekTo = fullDuration / 2.0;
     26                  var truncatedDuration = seekTo / 2.0;
     27 
     28                  mediaElement.play();
     29 
     30                  // Append all the segments
     31                  test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
     32                  test.expectEvent(mediaElement, 'playing', 'Playing triggered');
     33                  sourceBuffer.appendBuffer(mediaData);
     34 
     35                  test.waitForExpectedEvents(function()
     36                  {
     37                      test.expectEvent(mediaElement, 'seeking', 'seeking to seekTo');
     38                      test.expectEvent(mediaElement, 'timeupdate', 'timeupdate while seeking to seekTo');
     39                      test.expectEvent(mediaElement, 'seeked', 'seeked to seekTo');
     40                      mediaElement.currentTime = seekTo;
     41                      assert_true(mediaElement.seeking, 'mediaElement.seeking (to seekTo)');
     42                  });
     43 
     44                  test.waitForExpectedEvents(function()
     45                  {
     46                      assert_greater_than_equal(mediaElement.currentTime, seekTo, 'Playback time has reached seekTo');
     47                      assert_false(mediaElement.seeking, 'mediaElement.seeking after seeked to seekTo');
     48 
     49                      assert_false(sourceBuffer.updating, 'sourceBuffer.updating');
     50 
     51                      sourceBuffer.remove(truncatedDuration, Infinity);
     52 
     53                      assert_true(sourceBuffer.updating, 'sourceBuffer.updating');
     54                      test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
     55                      test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
     56                      test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
     57                  });
     58 
     59                  test.waitForExpectedEvents(function()
     60                  {
     61                      assert_greater_than_equal(mediaElement.currentTime, seekTo, 'Playback time has reached seekTo');
     62                      assert_false(sourceBuffer.updating, 'sourceBuffer.updating');
     63 
     64                      // Remove will not remove partial frames, so the resulting duration is the highest end time
     65                      // of the track buffer ranges, and is greater than or equal to the highest coded frame
     66                      // presentation time across all track buffer ranges. We first obtain the intersected track buffer
     67                      // ranges end time and set the duration to that value.
     68                      truncatedDuration = sourceBuffer.buffered.end(sourceBuffer.buffered.length-1);
     69                      assert_less_than(truncatedDuration, seekTo,
     70                                       'remove has removed the current playback position from at least one track buffer');
     71 
     72                      mediaSource.duration = truncatedDuration;
     73                      test.expectEvent(mediaElement, 'seeking', 'Seeking to truncated duration');
     74 
     75                      // The actual duration may be slightly higher than truncatedDuration because the
     76                      // duration is adjusted upwards if necessary to be the highest end time across all track buffer
     77                      // ranges. Allow that increase here.
     78                      assert_less_than_equal(truncatedDuration, mediaSource.duration,
     79                                              'Duration should not be less than what was set');
     80                      // Here, we assume no test media coded frame duration is longer than 100ms.
     81                      assert_less_than(mediaSource.duration - truncatedDuration, 0.1);
     82 
     83                      // Update our truncatedDuration to be the actual new duration.
     84                      truncatedDuration = mediaSource.duration;
     85 
     86                      assert_true(mediaElement.seeking, 'Seeking after setting truncatedDuration');
     87                  });
     88 
     89                  test.waitForExpectedEvents(function()
     90                  {
     91                      assert_equals(mediaElement.currentTime, truncatedDuration,
     92                                    'Playback time is truncatedDuration while seeking');
     93                      assert_true(mediaElement.seeking, 'mediaElement.seeking while seeking to truncatedDuration');
     94                      assert_equals(mediaElement.duration, truncatedDuration,
     95                                    'mediaElement truncatedDuration during seek to it');
     96                      assert_equals(mediaSource.duration, truncatedDuration,
     97                                    'mediaSource truncatedDuration during seek to it');
     98 
     99                      testFunction(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData,
    100                                   truncatedDuration);
    101                  });
    102              }, description, options);
    103          }
    104 
    105          mediasource_truncated_duration_seek_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer,
    106                                                            mediaData, truncatedDuration)
    107          {
    108              // Tests that duration truncation below current playback position
    109              // starts seek to new duration.
    110              test.done();
    111          }, 'Test seek starts on duration truncation below currentTime');
    112 
    113          mediasource_truncated_duration_seek_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer,
    114                                                            mediaData, truncatedDuration)
    115          {
    116              // The duration has been truncated at this point, and there is an
    117              // outstanding seek pending.
    118              test.expectEvent(sourceBuffer, 'updateend', 'updateend after appending more data');
    119 
    120              test.expectEvent(mediaElement, 'timeupdate', 'timeupdate while finishing seek to truncatedDuration');
    121              test.expectEvent(mediaElement, 'seeked', 'seeked to truncatedDuration');
    122 
    123              // Allow seek to complete by appending more data beginning at the
    124              // truncated duration timestamp.
    125              sourceBuffer.timestampOffset = truncatedDuration;
    126              sourceBuffer.appendBuffer(mediaData);
    127 
    128              test.waitForExpectedEvents(function()
    129              {
    130                  assert_greater_than_equal(mediaElement.currentTime, truncatedDuration,
    131                                            'Playback time has reached truncatedDuration');
    132                  assert_approx_equals(mediaElement.duration, truncatedDuration + segmentInfo.duration, 0.05,
    133                                       'mediaElement duration increased by new append');
    134                  assert_equals(mediaSource.duration, mediaElement.duration,
    135                                'mediaSource duration increased by new append');
    136                  assert_false(mediaElement.seeking, 'mediaElement.seeking after seeked to truncatedDuration');
    137 
    138                  test.done();
    139              });
    140          }, 'Test appendBuffer completes previous seek to truncated duration');
    141 
    142          mediasource_truncated_duration_seek_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer,
    143                                                            mediaData, truncatedDuration)
    144          {
    145              // The duration has been truncated at this point, and there is an
    146              // outstanding seek pending.
    147              test.expectEvent(mediaSource, 'sourceended', 'endOfStream acknowledged');
    148 
    149              test.expectEvent(mediaElement, 'timeupdate', 'timeupdate while finishing seek to truncatedDuration');
    150              test.expectEvent(mediaElement, 'seeked', 'seeked to truncatedDuration');
    151 
    152              // Call endOfStream() to complete the pending seek.
    153              mediaSource.endOfStream();
    154 
    155              test.waitForExpectedEvents(function()
    156              {
    157                  assert_greater_than_equal(mediaElement.currentTime, truncatedDuration,
    158                                'Playback time has reached truncatedDuration');
    159                  // The mediaSource.readyState is "ended". Buffered ranges have been adjusted to the longest track.
    160                  truncatedDuration = sourceBuffer.buffered.end(sourceBuffer.buffered.length-1);
    161                  assert_equals(mediaElement.duration, truncatedDuration,
    162                                'mediaElement truncatedDuration after seek to it');
    163                  assert_equals(mediaSource.duration, truncatedDuration,
    164                                'mediaSource truncatedDuration after seek to it');
    165                  assert_false(mediaElement.seeking, 'mediaElement.seeking after seeked to truncatedDuration');
    166 
    167                  test.done();
    168              });
    169          }, 'Test endOfStream completes previous seek to truncated duration');
    170 
    171          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
    172          {
    173              assert_greater_than(segmentInfo.duration, 2, 'Sufficient test media duration');
    174 
    175              var fullDuration = segmentInfo.duration;
    176              var newDuration = 0.5;
    177 
    178              var expectedDurationChangeEventCount = 1;
    179              var durationchangeEventCounter = 0;
    180              var durationchangeEventHandler = test.step_func(function(event)
    181              {
    182                  assert_equals(mediaElement.duration, mediaSource.duration, 'mediaElement newDuration');
    183                  // Final duration may be greater than originally set as per MSE's 2.4.6 Duration change
    184                  // Adjust newDuration accordingly.
    185                  assert_less_than_equal(newDuration, mediaSource.duration, 'mediaSource newDuration');
    186                  durationchangeEventCounter++;
    187              });
    188 
    189              mediaElement.play();
    190 
    191              // Append all the segments
    192              test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
    193              test.expectEvent(mediaElement, 'playing', 'Playing triggered');
    194              sourceBuffer.appendBuffer(mediaData);
    195 
    196              test.waitForExpectedEvents(function()
    197              {
    198                  assert_less_than(mediaElement.currentTime, newDuration / 2, 'mediaElement currentTime');
    199 
    200                  assert_false(sourceBuffer.updating, "updating");
    201 
    202                  // Truncate duration. This should result in one 'durationchange' fired.
    203                  sourceBuffer.remove(newDuration, Infinity);
    204 
    205                  assert_true(sourceBuffer.updating, "updating");
    206                  test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
    207                  test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
    208                  test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
    209              });
    210 
    211              test.waitForExpectedEvents(function()
    212              {
    213                  // Media load also fires 'durationchange' event, so only start counting them now.
    214                  mediaElement.addEventListener('durationchange', durationchangeEventHandler);
    215 
    216                  assert_false(sourceBuffer.updating, "updating");
    217 
    218                  // Truncate duration. This should result in one 'durationchange' fired.
    219                  mediaSource.duration = newDuration;
    220 
    221                  // Final duration may be greater than originally set as per MSE's 2.4.6 Duration change
    222                  // Adjust newDuration accordingly.
    223                  assert_true(newDuration <= mediaSource.duration, 'adjusted duration');
    224                  newDuration = mediaSource.duration;
    225 
    226                  // Set duration again to make sure it does not trigger another 'durationchange' event.
    227                  mediaSource.duration = newDuration;
    228 
    229                  // Mark endOfStream so that playback can reach 'ended' at the new duration.
    230                  test.expectEvent(mediaSource, 'sourceended', 'endOfStream acknowledged');
    231                  mediaSource.endOfStream();
    232 
    233                  // endOfStream can change duration slightly.
    234                  // Allow for one more 'durationchange' event only in this case.
    235                  var currentDuration = mediaSource.duration;
    236                  if (currentDuration != newDuration) {
    237                      newDuration = currentDuration;
    238                      ++expectedDurationChangeEventCount;
    239                  }
    240 
    241                  // Allow media to play to end while counting 'durationchange' events.
    242                  test.expectEvent(mediaElement, 'ended', 'Playback ended');
    243                  test.waitForExpectedEvents(function()
    244                  {
    245                      mediaElement.removeEventListener('durationchange', durationchangeEventHandler);
    246                      assert_equals(durationchangeEventCounter, expectedDurationChangeEventCount, 'durationchanges');
    247                      test.done();
    248                  });
    249              });
    250          }, 'Test setting same duration multiple times does not fire duplicate durationchange');
    251 
    252          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
    253          {
    254              assert_greater_than(segmentInfo.duration, 2, 'Sufficient test media duration');
    255 
    256              var fullDuration = segmentInfo.duration;
    257              var newDuration = fullDuration / 2;
    258 
    259              // Append all the segments
    260              test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
    261              test.expectEvent(mediaElement, 'loadedmetadata', 'mediaElement');
    262              sourceBuffer.appendBuffer(mediaData);
    263 
    264              test.waitForExpectedEvents(function()
    265              {
    266                  assert_false(sourceBuffer.updating, "updating");
    267 
    268                  assert_throws_dom("InvalidStateError", function()
    269                  {
    270                      mediaSource.duration = newDuration;
    271                  }, "duration");
    272 
    273                  test.done();
    274              });
    275          }, 'Test setting the duration to less than the highest starting presentation timestamp will throw');
    276 
    277          mediasource_test(function(test, mediaElement, mediaSource)
    278          {
    279              mediaElement.addEventListener("error", test.unreached_func("Unexpected event 'error'"));
    280              MediaSourceUtil.fetchManifestAndData(test, manifestFilenameAudio, function(typeAudio, dataAudio)
    281              {
    282                  MediaSourceUtil.fetchManifestAndData(test, manifestFilenameVideo, function(typeVideo, dataVideo)
    283                  {
    284                      var sourceBufferAudio = mediaSource.addSourceBuffer(typeAudio);
    285                      var sourceBufferVideo = mediaSource.addSourceBuffer(typeVideo);
    286                      var newDuration = 1.2;
    287 
    288                      sourceBufferAudio.appendWindowEnd = 2.0;
    289                      sourceBufferAudio.appendWindowStart = newDuration / 2.0;
    290                      sourceBufferAudio.appendBuffer(dataAudio);
    291 
    292                      sourceBufferVideo.appendWindowEnd = 2.0;
    293                      sourceBufferVideo.appendWindowStart = newDuration * 1.3;
    294                      sourceBufferVideo.appendBuffer(dataVideo);
    295 
    296                      test.expectEvent(sourceBufferAudio, "updateend");
    297                      test.expectEvent(sourceBufferVideo, "updateend");
    298                      test.waitForExpectedEvents(function()
    299                      {
    300                          assert_equals(sourceBufferAudio.buffered.length, 1);
    301                          assert_equals(sourceBufferVideo.buffered.length, 1);
    302                          assert_less_than(sourceBufferAudio.buffered.start(0), newDuration);
    303                          assert_greater_than(sourceBufferVideo.buffered.start(0), newDuration);
    304                          assert_throws_dom("InvalidStateError", function () { mediaSource.duration = newDuration; });
    305                          test.done();
    306                      });
    307                  });
    308              });
    309          }, "Truncating the duration throws an InvalidStateError exception when new duration is less than the highest buffered range start time of one of the track buffers");
    310 
    311          mediasource_test(function(test, mediaElement, mediaSource)
    312          {
    313              mediaElement.addEventListener("error", test.unreached_func("Unexpected event 'error'"));
    314              MediaSourceUtil.fetchManifestAndData(test, manifestFilenameAudio, function(typeAudio, dataAudio)
    315              {
    316                  MediaSourceUtil.fetchManifestAndData(test, manifestFilenameVideo, function(typeVideo, dataVideo)
    317                  {
    318                      var sourceBufferAudio = mediaSource.addSourceBuffer(typeAudio);
    319                      var sourceBufferVideo = mediaSource.addSourceBuffer(typeVideo);
    320 
    321                      // Buffer audio [0.8,1.8)
    322                      sourceBufferAudio.timestampOffset = 0.8;
    323                      sourceBufferAudio.appendWindowEnd = 1.8;
    324                      sourceBufferAudio.appendBuffer(dataAudio);
    325 
    326                      // Buffer video [1.5,3)
    327                      sourceBufferVideo.timestampOffset = 1.5;
    328                      sourceBufferVideo.appendWindowEnd = 3;
    329                      sourceBufferVideo.appendBuffer(dataVideo);
    330 
    331                      test.expectEvent(sourceBufferAudio, "updateend");
    332                      test.expectEvent(sourceBufferVideo, "updateend");
    333                      test.waitForExpectedEvents(function()
    334                      {
    335                          var newDuration = 2.0;
    336 
    337                          // Verify the test setup
    338                          assert_equals(sourceBufferAudio.buffered.length, 1);
    339                          assert_equals(sourceBufferVideo.buffered.length, 1);
    340                          assert_greater_than(sourceBufferAudio.buffered.end(0), 1.5);
    341                          assert_less_than(sourceBufferAudio.buffered.end(0), newDuration);
    342                          assert_less_than(sourceBufferVideo.buffered.start(0), newDuration);
    343                          assert_greater_than(sourceBufferVideo.buffered.end(0), newDuration + 0.5);
    344 
    345                          // Verify the expected error
    346                          // We assume relocated test video has at least one coded
    347                          // frame presentation interval which fits in [>2.0,>2.5)
    348                          assert_throws_dom("InvalidStateError", function () { mediaSource.duration = newDuration; });
    349                          test.done();
    350                      });
    351                  });
    352              });
    353          }, "Truncating the duration throws an InvalidStateError exception when new duration is less than a buffered coded frame presentation time");
    354 
    355          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
    356          {
    357              assert_less_than(segmentInfo.duration, 60, 'Sufficient test media duration');
    358              sourceBuffer.appendBuffer(mediaData);
    359              test.expectEvent(sourceBuffer, 'updateend', 'Media data appended to the SourceBuffer');
    360              test.waitForExpectedEvents(function()
    361              {
    362                  mediaSource.duration = 60;
    363                  assert_false(sourceBuffer.updating, 'No SourceBuffer update when duration is increased');
    364                  test.done();
    365              });
    366          }, 'Increasing the duration does not trigger any SourceBuffer update');
    367 
    368          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
    369          {
    370              assert_greater_than(segmentInfo.duration, 2, 'Sufficient test media duration');
    371              mediaElement.play();
    372              sourceBuffer.appendBuffer(mediaData);
    373              test.expectEvent(sourceBuffer, 'updateend', 'Media data appended to the SourceBuffer');
    374              test.waitForExpectedEvents(function()
    375              {
    376                  mediaSource.duration = 60;
    377                  assert_false(sourceBuffer.updating, 'No SourceBuffer update when duration is increased');
    378                  test.done();
    379              });
    380          }, 'Increasing the duration during media playback does not trigger any SourceBuffer update');
    381        </script>
    382    </body>
    383 </html>