Bug 1280613 - P3. Mochitests. r=bryce
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 11 May 2018 09:01:25 +0200
changeset 472688 38d9226183f0762e3182b16d0c1927e912961f47
parent 472687 bc87e9eef2b87159f95552163901225efd07d40d
child 472689 db12e77242559a3aac6d80d705deaa770269e603
push id9374
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:43:20 +0000
treeherdermozilla-beta@160e085dfb0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbryce
bugs1280613
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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>