Bug 1358399. P6 - rewrite SetupEME() using the new helper functions and fix its callers. draft
authorJW Wang <jwwang@mozilla.com>
Fri, 21 Apr 2017 18:06:31 +0800
changeset 568430 9b6118ecd19f331dd511532f799ae3d243a6a75b
parent 568429 1c2763d3aec1ea867f705757b99393b909afd931
child 568431 6689f60f453f542b0c110a8682fa78be8388847a
push id55869
push userjwwang@mozilla.com
push dateWed, 26 Apr 2017 06:34:41 +0000
bugs1358399
milestone55.0a1
Bug 1358399. P6 - rewrite SetupEME() using the new helper functions and fix its callers. MozReview-Commit-ID: KUXhvPIuXry
dom/media/test/eme.js
dom/media/test/test_eme_canvas_blocked.html
dom/media/test/test_eme_stream_capture_blocked_case2.html
dom/media/test/test_eme_stream_capture_blocked_case3.html
--- a/dom/media/test/eme.js
+++ b/dom/media/test/eme.js
@@ -406,188 +406,39 @@ function CleanUpMedia(v) {
 /*
  * Close all sessions and clean up the |v| element.
  */
 function CloseSessions(v, sessions) {
   return Promise.all(sessions.map(s => s.close()))
   .then(CleanUpMedia(v));
 }
 
-function SetupEME(test, token, params)
-{
-  var v = document.createElement("video");
-  v.sessions = [];
-
-  v.closeSessions = function() {
-    return Promise.all(v.sessions.map(s => s.close().then(() => s.closed))).then(
-      () => {
-        v.setMediaKeys(null);
-        if (v.parentNode) {
-          v.remove();
-        }
-        v.onerror = null;
-        v.src = null;
-      });
-  };
+/*
+ * Set up media keys and source buffers for the media element.
+ * Return a promise resolved when all key sessions are updated or rejected
+ * if any failure.
+ */
+function SetupEME(v, test, token, loadParams) {
+  let p = new EMEPromise;
 
-  // Log events dispatched to make debugging easier...
-  [ "canplay", "canplaythrough", "ended", "error", "loadeddata",
-    "loadedmetadata", "loadstart", "pause", "play", "playing", "progress",
-    "stalled", "suspend", "waiting", "waitingforkey",
-  ].forEach(function (e) {
-    v.addEventListener(e, function(event) {
-      Log(token, "" + e);
-    });
-  });
-
-  // Finish the test when error is encountered.
-  v.onerror = bail(token + " got error event");
-
-  var onSetKeysFail = (params && params.onSetKeysFail)
-    ? params.onSetKeysFail
-    : bail(token + " Failed to set MediaKeys on <video> element");
-
-  // null: No session management in progress, just go ahead and update the session.
-  // [...]: Session management in progress, add {initDataType, initData} to
-  //        this queue to get it processed when possible.
-  var initDataQueue = [];
-  function pushInitData(ev)
-  {
-    if (initDataQueue === null) {
-      initDataQueue = [];
-    }
-    initDataQueue.push(ev);
-    if (params && params.onInitDataQueued) {
-      params.onInitDataQueued(ev, ev.initDataType, StringToHex(ArrayBufferToString(ev.initData)));
-    }
+  v.onerror = function() {
+    p.reject(`${token} got an error event.`);
   }
 
-  function processInitDataQueue()
-  {
-    function maybeResolveInitDataPromise() {
-      if (params && params.initDataPromise) {
-        params.initDataPromise.resolve();
-      }
-    }
-    if (initDataQueue === null) {
-      maybeResolveInitDataPromise();
-      return;
-    }
-    // If we're processed all our init data null the queue to indicate encrypted event handled.
-    if (initDataQueue.length === 0) {
-      initDataQueue = null;
-      maybeResolveInitDataPromise();
-      return;
-    }
-    var ev = initDataQueue.shift();
-
-    var sessionType = (params && params.sessionType) ? params.sessionType : "temporary";
-    Log(token, "createSession(" + sessionType + ") for (" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ")");
-    var session = v.mediaKeys.createSession(sessionType);
-    if (params && params.onsessioncreated) {
-      params.onsessioncreated(session);
-    }
-    v.sessions.push(session);
-
-    return new Promise(function (resolve, reject) {
-      session.addEventListener("message", UpdateSessionFunc(test, token, sessionType, resolve, reject));
-      Log(token, "session[" + session.sessionId + "].generateRequest(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ")");
-      session.generateRequest(ev.initDataType, ev.initData).catch(function(reason) {
-        // Reject the promise if generateRequest() failed. Otherwise it will
-        // be resolve in UpdateSessionFunc().
-        bail(token + ": session[" + session.sessionId + "].generateRequest(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") failed")(reason);
-        reject();
-      });
-    })
-
-    .then(function(aSession) {
-      Log(token, "session[" + session.sessionId + "].generateRequest(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") succeeded");
-      if (params && params.onsessionupdated) {
-        params.onsessionupdated(aSession);
-      }
-      processInitDataQueue();
-    });
-  }
-
-  function streamType(type) {
-    var x = test.tracks.find(o => o.name == type);
-    return x ? x.type : undefined;
-  }
-
-  // If sessions are to be delayed we won't peform any processing until the
-  // callback the assigned here is called by the test.
-  if (params && params.delaySessions) {
-    params.ProcessSessions = processInitDataQueue;
-  }
+  Promise.all([
+    LoadInitData(v, test, token),
+    CreateAndSetMediaKeys(v, test, token),
+    LoadTest(test, v, token, loadParams)])
+  .then(values => {
+    let initData = values[0];
+    return ProcessInitData(v, test, token, initData);
+  })
+  .then(p.resolve, p.reject);
 
-  // Is this the first piece of init data we're processing?
-  var firstInitData = true;
-  v.addEventListener("encrypted", function(ev) {
-    if (firstInitData) {
-      Log(token, "got first encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + "), setup session");
-      firstInitData = false;
-      pushInitData(ev);
-
-      function chain(promise, onReject) {
-        return promise.then(function(value) {
-          return Promise.resolve(value);
-        }).catch(function(reason) {
-          onReject(reason);
-          return Promise.reject();
-        })
-      }
-
-      var options = { initDataTypes: [ev.initDataType] };
-      if (streamType("video")) {
-        options.videoCapabilities = [{contentType: streamType("video")}];
-      }
-      if (streamType("audio")) {
-        options.audioCapabilities = [{contentType: streamType("audio")}];
-      }
-
-      var p = navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, [options]);
-      var r = bail(token + " Failed to request key system access.");
-      chain(p, r)
-      .then(function(keySystemAccess) {
-        var p = keySystemAccess.createMediaKeys();
-        var r = bail(token +  " Failed to create MediaKeys object");
-        return chain(p, r);
-      })
-
-      .then(function(mediaKeys) {
-        Log(token, "created MediaKeys object ok");
-        mediaKeys.sessions = [];
-        var p = v.setMediaKeys(mediaKeys);
-        return chain(p, onSetKeysFail);
-      })
-
-      .then(function() {
-        Log(token, "set MediaKeys on <video> element ok");
-        if (params && params.onMediaKeysSet) {
-          params.onMediaKeysSet();
-        }
-        if (!(params && params.delaySessions)) {
-          processInitDataQueue();
-        }
-      })
-    } else {
-      if (params && params.delaySessions) {
-        Log(token, "got encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") event, queue it in because we're delaying sessions");
-        pushInitData(ev);
-      } else if (initDataQueue !== null) {
-        Log(token, "got encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") event, queue it for later session update");
-        pushInitData(ev);
-      } else {
-        Log(token, "got encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") event, update session now");
-        pushInitData(ev);
-        processInitDataQueue();
-      }
-    }
-  });
-  return v;
+  return p.promise;
 }
 
 function SetupEMEPref(callback) {
   var prefs = [
     [ "media.mediasource.enabled", true ],
     [ "media.mediasource.webm.enabled", true ],
     [ "media.eme.vp9-in-mp4.enabled", true ],
   ];
--- a/dom/media/test/test_eme_canvas_blocked.html
+++ b/dom/media/test/test_eme_canvas_blocked.html
@@ -11,21 +11,17 @@
 <pre id="test">
 <script class="testbody" type="text/javascript">
 var manager = new MediaTestManager;
 
 function startTest(test, token)
 {
   manager.started(token);
 
-  var sessions = [];
-  // Will be resolved when all initData are processed.
-  let initDataPromise = new EMEPromise;
-
-  var v = SetupEME(test, token, { initDataPromise: initDataPromise });
+  let v = document.createElement("video");
   v.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this.
 
   var p1 = new EMEPromise;
   v.addEventListener("loadeddata", function(ev) {
     var video = ev.target;
     var canvas = document.createElement("canvas");
     canvas.width = video.videoWidth;
     canvas.height = video.videoHeight;
@@ -36,18 +32,24 @@ function startTest(test, token)
       ctx.drawImage(video, 0, 0);
     } catch (ex) {
       threwError = true;
     }
     ok(threwError, TimeStamp(token) + " - Should throw an error when trying to draw EME video to canvas.");
     p1.resolve();
   });
 
-  var p2 = LoadTest(test, v, token, { onlyLoadFirstFragments:2, noEndOfStream:false });
-  EMEPromiseAll(v, token, [p1.promise, p2, initDataPromise.promise]);
+  let p2 = SetupEME(v, test, token, { noEndOfStream:false });
+
+  Promise.all([p1.promise, p2])
+  .catch(reason => ok(false, reason))
+  .then(() => {
+    CleanUpMedia(v);
+    manager.finished(token);
+  });
 }
 
 function beginTest() {
   manager.runTests(gEMETests, startTest);
 }
 
 if (!IsMacOSSnowLeopardOrEarlier()) {
   SimpleTest.waitForExplicitFinish();
--- a/dom/media/test/test_eme_stream_capture_blocked_case2.html
+++ b/dom/media/test/test_eme_stream_capture_blocked_case2.html
@@ -17,32 +17,40 @@ function startTest(test, token)
   // Three cases:
   // 1. setting MediaKeys on an element captured by MediaElementSource should fail, and
   // 2. creating a MediaElementSource on a media element with a MediaKeys should fail, and
   // 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
 
   // Case 2. creating a MediaElementSource on a media element with a MediaKeys should fail.
   var p1 = new EMEPromise;
   var case2token = token + "_case2";
-  var v2 = SetupEME(test, case2token);
+  let v2 = document.createElement("video");
+
   v2.addEventListener("loadeddata", function(ev) {
     ok(true, case2token + " should reach loadeddata");
     var threw = false;
     try {
       var context = new AudioContext();
       var node = context.createMediaElementSource(v2);
     } catch (e) {
       threw = true;
     }
     ok(threw, "Should throw an error creating a MediaElementSource on an EME video.");
     p1.resolve();
   });
+
   manager.started(case2token);
-  var p2 = LoadTest(test, v2, case2token, { onlyLoadFirstFragments:2, noEndOfStream:false });
-  EMEPromiseAll(v2, case2token, [p1.promise, p2]);
+  let p2 = SetupEME(v2, test, case2token, { noEndOfStream:false });
+
+  Promise.all([p1.promise, p2])
+  .catch(reason => ok(false, reason))
+  .then(() => {
+    CleanUpMedia(v2);
+    manager.finished(case2token);
+  });
 }
 
 function beginTest() {
   manager.runTests(gEMETests, startTest);
 }
 
 if (!IsMacOSSnowLeopardOrEarlier()) {
   SimpleTest.waitForExplicitFinish();
--- a/dom/media/test/test_eme_stream_capture_blocked_case3.html
+++ b/dom/media/test/test_eme_stream_capture_blocked_case3.html
@@ -17,31 +17,39 @@ function startTest(test, token)
   // Three cases:
   // 1. setting MediaKeys on an element captured by MediaElementSource should fail, and
   // 2. creating a MediaElementSource on a media element with a MediaKeys should fail, and
   // 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
 
   // Case 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
   var p1 = new EMEPromise;
   var case3token = token + "_case3";
-  var v3 = SetupEME(test, case3token);
+  let v3 = document.createElement("video");
+
   v3.addEventListener("loadeddata", function(ev) {
     ok(true, TimeStamp(case3token) + " should reach loadeddata");
     var threw = false;
     try {
       var stream = v3.mozCaptureStreamUntilEnded();
     } catch (e) {
       threw = true;
     }
     ok(threw, TimeStamp(case3token) + " Should throw an error calling mozCaptureStreamUntilEnded an EME video.");
     p1.resolve();
   });
+
   manager.started(case3token);
-  var p2 = LoadTest(test, v3, case3token, { onlyLoadFirstFragments:2, noEndOfStream:false });
-  EMEPromiseAll(v3, case3token, [p1.promise, p2]);
+  let p2 = SetupEME(v3, test, case3token, { noEndOfStream:false });
+
+  Promise.all([p1.promise, p2])
+  .catch(reason => ok(false, reason))
+  .then(() => {
+    CleanUpMedia(v3);
+    manager.finished(case3token);
+  });
 }
 
 function beginTest() {
   manager.runTests(gEMETests, startTest);
 }
 
 if (!IsMacOSSnowLeopardOrEarlier()) {
   SimpleTest.waitForExplicitFinish();