Bug 1280613 - P3. Mochitests. r?bryce draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 11 May 2018 09:01:25 +0200
changeset 794579 ed2e718f6a0e2576a86178f05fb7f7d5881e8217
parent 794578 bd59c1348d359ab57e7d5b3c0e4e5df60ab5eeef
push id109720
push userbmo:jyavenard@mozilla.com
push dateSun, 13 May 2018 14:54:13 +0000
reviewersbryce
bugs1280613
milestone62.0a1
Bug 1280613 - P3. Mochitests. r?bryce MozReview-Commit-ID: 5FIe9qfNZWd
dom/media/mediasource/test/mediasource.js
dom/media/mediasource/test/mochitest.ini
dom/media/mediasource/test/test_ExperimentalAsync.html
--- a/dom/media/mediasource/test/mediasource.js
+++ b/dom/media/mediasource/test/mediasource.js
@@ -110,16 +110,46 @@ function fetchAndLoad(sb, prefix, chunks
     var rv = Promise.resolve();
     for (var chunk of chunks) {
       rv = rv.then(loadSegment.bind(null, sb, buffers[chunk]));
     }
     return rv;
   });
 }
 
+function loadSegmentAsync(sb, typedArrayOrArrayBuffer) {
+  var typedArray = (typedArrayOrArrayBuffer instanceof ArrayBuffer) ? new Uint8Array(typedArrayOrArrayBuffer)
+                                                                    : typedArrayOrArrayBuffer;
+  info(`Loading buffer2: [${typedArray.byteOffset}, ${typedArray.byteOffset + typedArray.byteLength})`);
+  var beforeBuffered = timeRangeToString(sb.buffered);
+  return sb.appendBufferAsync(typedArray).then(() => {
+    var afterBuffered = timeRangeToString(sb.buffered);
+    info(`SourceBuffer buffered ranges grew from ${beforeBuffered} to ${afterBuffered}`);
+  });
+}
+
+function fetchAndLoadAsync(sb, prefix, chunks, suffix) {
+
+  // Fetch the buffers in parallel.
+  var buffers = {};
+  var fetches = [];
+  for (var chunk of chunks) {
+    fetches.push(fetchWithXHR(prefix + chunk + suffix).then(((c, x) => buffers[c] = x).bind(null, chunk)));
+  }
+
+  // Load them in series, as required per spec.
+  return Promise.all(fetches).then(function() {
+    var rv = Promise.resolve();
+    for (var chunk of chunks) {
+      rv = rv.then(loadSegmentAsync.bind(null, sb, buffers[chunk]));
+    }
+    return rv;
+  });
+}
+
 //Register timeout function to dump debugging logs.
 SimpleTest.registerTimeoutFunction(function() {
   for (var v of document.getElementsByTagName("video")) {
     v.mozDumpDebugInfo();
   }
   for (var a of document.getElementsByTagName("audio")) {
     a.mozDumpDebugInfo();
   }
--- a/dom/media/mediasource/test/mochitest.ini
+++ b/dom/media/mediasource/test/mochitest.ini
@@ -76,16 +76,18 @@ skip-if = toolkit == 'android' # Not sup
 skip-if = toolkit == 'android' # Not supported on android
 [test_EndedEvent.html]
 skip-if = android_version == '22' || toolkit == 'android' # bug 1358640, bug 1401090
 [test_EndOfStream.html]
 [test_EndOfStream_mp4.html]
 skip-if = toolkit == 'android' # Not supported on android
 [test_Eviction_mp4.html]
 skip-if = android_version == '15' # Not supported on Android(Bug 1358271)
+[test_ExperimentalAsync.html]
+skip-if = android_version == '22' || toolkit == 'android' # bug 1341519, bug 1401090
 [test_FrameSelection.html]
 skip-if = android_version == '22' || toolkit == 'android' # bug 1341519, bug 1401090
 [test_FrameSelection_mp4.html]
 skip-if = toolkit == 'android' # Not supported on android
 [test_HaveMetadataUnbufferedSeek.html]
 skip-if = android_version == '22' || toolkit == 'android' # bug 1342247, bug 1401090
 [test_HaveMetadataUnbufferedSeek_mp4.html]
 skip-if = toolkit == 'android' # Not supported on android
new file mode 100644
--- /dev/null
+++ b/dom/media/mediasource/test/test_ExperimentalAsync.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=windows-1252">
+  <title>MSE: testing removeAsync and appendBufferAsync</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="mediasource.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test"><script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+addMSEPrefs(
+  ["media.mediasource.eviction_threshold.audio", 524288],
+  ["media.dormant-on-pause-timeout-ms", -1], // FIXME: bug 1319292
+  ["media.mediasource.experimental.enabled", true]
+);
+
+// We fill up the source buffer with audio data until the buffer is full.
+// We ensure that QuotaExceededError is thrown once the buffer is full.
+// We then seek to half the content. By that time, another appendBuffer must succeed
+// as the auto-eviction would succeed (removing all data prior currentTime)
+// The test then fills the audio buffer and plays until the end.
+
+// Fill up the SourceBuffer by appending data repeatedly via doAppendDataFunc until
+// an exception is thrown.
+async function fillUpSourceBuffer(sourceBuffer, doAppendDataFunc, onCaughtExceptionCallback) {
+  try {
+    // We are appending data repeatedly in sequence mode, there should be no gaps.
+    while(true) {
+      ok(sourceBuffer.buffered.length <= 1, "there should be no gap in buffered ranges.");
+      await doAppendDataFunc();
+    }
+  } catch (ex) {
+    ok(true, "appendBuffer promise got rejected");
+    onCaughtExceptionCallback(ex);
+  }
+}
+
+runWithMSE(async function(ms, el) {
+  el.controls = true;
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  let audiosb = ms.addSourceBuffer("audio/mp4");
+
+  // Test removeAsync
+  audiosb.mode = "sequence";
+  var audioInitBuffer = await fetchWithXHR("bipbop/bipbop_audioinit.mp4");
+  await audiosb.appendBufferAsync(audioInitBuffer);
+  var audioBuffer = await fetchWithXHR("bipbop/bipbop_audio1.m4s");
+  fillUpSourceBuffer(audiosb,
+    function() { // doAppendDataFunc
+      return audiosb.appendBufferAsync(audioBuffer);
+    },
+    async function(ex) { // onCaughtExceptionCallback
+      is(ex.name, "QuotaExceededError", "QuotaExceededError thrown");
+      is(audiosb.buffered.end(0), el.duration, "Duration is end of buffered range");
+      let seekTime = audiosb.buffered.end(0) / 2;
+      el.currentTime = seekTime;
+      await once(el, "seeked");
+      dump("dump: seeked to " + seekTime);
+      is(el.currentTime, seekTime, "correctly seeked to " + seekTime);
+      await audiosb.appendBufferAsync(audioBuffer).catch(function(ex) {
+        ok(false, "Shouldn't throw another time when data can be evicted");
+        el.mozDumpDebugInfo();
+        SimpleTest.finish();
+      });
+      // Test that an error in remove return a rejected promise
+      await audiosb.removeAsync(5, 0).catch(async function(ex) {
+        ok(true, "remove promise got rejected with end <= start");
+        is(ex.name, "TypeError");
+        await audiosb.removeAsync(ms.duration + 1, Infinity).catch(async function(ex) {
+          ok(true, "remove promise got rejected with start > duration");
+          is(ex.name, "TypeError");
+          await audiosb.removeAsync(0, Infinity).catch(function(ex) {
+            ok(false, "shouldn't throw");
+          });
+          ok(true, "remove succeeded");
+          is(audiosb.buffered.length, 0, "buffered should be empty");
+          audiosb.mode = "segment";
+          audiosb.timestampOffset = 0;
+          el.currentTime = 0;
+          await fetchAndLoadAsync(audiosb, "bipbop/bipbop_audio", range(1, 4), ".m4s");
+          ms.endOfStream();
+          el.play();
+          await once(el, "ended");
+          is(el.currentTime, el.duration, "played to the end");
+          SimpleTest.finish();
+          throw ex; // ensure we don't fallback on lines below.
+        });
+        ok(false, "should have returned an error");
+      });
+      ok(false, "should have returned an error");
+    }
+  );
+});
+
+</script>
+</pre>
+</body>
+</html>