Bug 1071482 - Factor out EME load/setup code, so it can be reused in other tests more easily. r=edwin
authorChris Pearce <cpearce@mozilla.com>
Tue, 28 Oct 2014 13:21:11 +1300
changeset 213051 34d86b491ac16a7322a66d3f6362761349bd510b
parent 213050 cc451b07de72c711aaaf464fa5638a62defaa45d
child 213052 396575d789e430d815fd2ab1126c165db19d2629
push id27738
push usercbook@mozilla.com
push dateThu, 30 Oct 2014 13:46:07 +0000
treeherdermozilla-central@1aa1b23d799e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersedwin
bugs1071482
milestone36.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 1071482 - Factor out EME load/setup code, so it can be reused in other tests more easily. r=edwin
dom/media/test/eme.js
dom/media/test/mochitest.ini
dom/media/test/test_encryptedMediaExtensions.html
new file mode 100644
--- /dev/null
+++ b/dom/media/test/eme.js
@@ -0,0 +1,174 @@
+const KEYSYSTEM_TYPE = "org.w3.clearkey";
+
+function bail(message)
+{
+  return function(err) {
+    ok(false, message);
+    if (err) {
+      info(err);
+    }
+    SimpleTest.finish();
+  }
+}
+
+function ArrayBufferToString(arr)
+{
+  var str = '';
+  var view = new Uint8Array(arr);
+  for (var i = 0; i < view.length; i++) {
+    str += String.fromCharCode(view[i]);
+  }
+  return str;
+}
+
+function StringToArrayBuffer(str)
+{
+  var arr = new ArrayBuffer(str.length);
+  var view = new Uint8Array(arr);
+  for (var i = 0; i < str.length; i++) {
+    view[i] = str.charCodeAt(i);
+  }
+  return arr;
+}
+
+function Base64ToHex(str)
+{
+  var bin = window.atob(str.replace(/-/g, "+").replace(/_/g, "/"));
+  var res = "";
+  for (var i = 0; i < bin.length; i++) {
+    res += ("0" + bin.charCodeAt(i).toString(16)).substr(-2);
+  }
+  return res;
+}
+
+function HexToBase64(hex)
+{
+  var bin = "";
+  for (var i = 0; i < hex.length; i += 2) {
+    bin += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
+  }
+  return window.btoa(bin).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
+}
+
+function UpdateSessionFunc(test) {
+  return function(ev) {
+    var msgStr = ArrayBufferToString(ev.message);
+    var msg = JSON.parse(msgStr);
+
+    info("got message from CDM: " + msgStr);
+    is(msg.type, test.sessionType, "Key session type should match");
+    ok(msg.kids, "message event should contain key ID array");
+
+    var outKeys = [];
+
+    for (var i = 0; i < msg.kids.length; i++) {
+      var id64 = msg.kids[i];
+      var idHex = Base64ToHex(msg.kids[i]).toLowerCase();
+      var key = test.keys[idHex];
+
+      if (key) {
+        info("found key " + key + " for key id " + idHex);
+        outKeys.push({
+          "kty":"oct",
+          "alg":"A128KW",
+          "kid":id64,
+          "k":HexToBase64(key)
+        });
+      } else {
+        bail("Couldn't find key for key id " + idHex);
+      }
+    }
+
+    var update = JSON.stringify({
+      "keys" : outKeys,
+      "type" : msg.type
+    });
+    info("sending update message to CDM: " + update);
+
+    ev.target.update(StringToArrayBuffer(update)).then(function() {
+      info("MediaKeySession update ok!");
+    }, bail("MediaKeySession update failed"));
+  }
+}
+
+function PlayFragmented(test, elem)
+{
+  return new Promise(function(resolve, reject) {
+    var ms = new MediaSource();
+    elem.src = URL.createObjectURL(ms);
+
+    var sb;
+    var curFragment = 0;
+
+    function addNextFragment() {
+      if (curFragment >= test.fragments.length) {
+        ms.endOfStream();
+        resolve();
+        return;
+      }
+
+      var fragmentFile = test.fragments[curFragment++];
+
+      var req = new XMLHttpRequest();
+      req.open("GET", fragmentFile);
+      req.responseType = "arraybuffer";
+
+      req.addEventListener("load", function() {
+        sb.appendBuffer(new Uint8Array(req.response));
+      });
+
+      info("fetching resource " + fragmentFile);
+      req.send(null);
+    }
+
+    ms.addEventListener("sourceopen", function () {
+      sb = ms.addSourceBuffer(test.type);
+      sb.addEventListener("updateend", addNextFragment);
+
+      addNextFragment();
+    })
+  });
+}
+
+// Returns a promise that is resovled when the media element is ready to have
+// its play() function called; when it's loaded MSE fragments, or once the load
+// has started for non-MSE video.
+function LoadTest(test, elem)
+{
+  if (test.fragments) {
+    return PlayFragmented(test, elem);
+  }
+
+  // This file isn't fragmented; set the media source normally.
+  return new Promise(function(resolve, reject) {
+    elem.src = test.name;
+    resolve();
+  });
+}
+
+function SetupEME(test, token, params)
+{
+  var v = document.createElement("video");
+
+  v.addEventListener("encrypted", function(ev) {
+    info(token + " got encrypted event");
+    MediaKeys.create(KEYSYSTEM_TYPE).then(function(mediaKeys) {
+      info(token + " created MediaKeys object ok");
+      mediaKeys.sessions = [];
+      return v.setMediaKeys(mediaKeys);
+    }, bail("failed to create MediaKeys object")).then(function() {
+      info(token + " set MediaKeys on <video> element ok");
+
+      var session = v.mediaKeys.createSession(test.sessionType);
+      if (params && params.onsessioncreated) {
+        params.onsessioncreated(session);
+      }
+      session.addEventListener("message", UpdateSessionFunc(test));
+      session.generateRequest(ev.initDataType, ev.initData).then(function() {
+      }, bail(token + " Failed to initialise MediaKeySession"));
+
+    }, bail(token + " Failed to set MediaKeys on <video> element"));
+  });
+
+  return v;
+}
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -135,16 +135,17 @@ support-files =
   detodos.opus
   detodos.opus^headers^
   detodos.webm
   detodos.webm^headers^
   dirac.ogg
   dirac.ogg^headers^
   dynamic_redirect.sjs
   dynamic_resource.sjs
+  eme.js
   gizmo-frag-cenc1.m4s
   gizmo-frag-cenc2.m4s
   gizmo-frag-cencinit.mp4
   file_access_controls.html
   fragment_noplay.js
   fragment_play.js
   gizmo.mp4
   gizmo.mp4^headers^
--- a/dom/media/test/test_encryptedMediaExtensions.html
+++ b/dom/media/test/test_encryptedMediaExtensions.html
@@ -1,162 +1,22 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Test Encrypted Media Extensions</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
+  <script type="text/javascript" src="eme.js"></script>
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 var manager = new MediaTestManager;
 
-const KEYSYSTEM_TYPE = "org.w3.clearkey";
-
-function bail(message)
-{
-  return function(err) {
-    ok(false, message);
-    if (err) {
-      info(err);
-    }
-    SimpleTest.finish();
-  }
-}
-
-function ArrayBufferToString(arr)
-{
-  var str = '';
-  var view = new Uint8Array(arr);
-  for (var i = 0; i < view.length; i++) {
-    str += String.fromCharCode(view[i]);
-  }
-  return str;
-}
-
-function StringToArrayBuffer(str)
-{
-  var arr = new ArrayBuffer(str.length);
-  var view = new Uint8Array(arr);
-  for (var i = 0; i < str.length; i++) {
-    view[i] = str.charCodeAt(i);
-  }
-  return arr;
-}
-
-function Base64ToHex(str)
-{
-  var bin = window.atob(str.replace(/-/g, "+").replace(/_/g, "/"));
-  var res = "";
-  for (var i = 0; i < bin.length; i++) {
-    res += ("0" + bin.charCodeAt(i).toString(16)).substr(-2);
-  }
-  return res;
-}
-
-function HexToBase64(hex)
-{
-  var bin = "";
-  for (var i = 0; i < hex.length; i += 2) {
-    bin += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
-  }
-  return window.btoa(bin).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
-}
-
-function UpdateSessionFunc(test) {
-  return function(ev) {
-    var msgStr = ArrayBufferToString(ev.message);
-    var msg = JSON.parse(msgStr);
-
-    info("got message from CDM: " + msgStr);
-    is(msg.type, test.sessionType, "Key session type should match");
-    ok(msg.kids, "message event should contain key ID array");
-
-    var outKeys = [];
-
-    for (var i = 0; i < msg.kids.length; i++) {
-      var id64 = msg.kids[i];
-      var idHex = Base64ToHex(msg.kids[i]).toLowerCase();
-      var key = test.keys[idHex];
-
-      if (key) {
-        info("found key " + key + " for key id " + idHex);
-        outKeys.push({
-          "kty":"oct",
-          "alg":"A128KW",
-          "kid":id64,
-          "k":HexToBase64(key)
-        });
-      } else {
-        bail("Couldn't find key for key id " + idHex);
-      }
-    }
-
-    var update = JSON.stringify({
-      "keys" : outKeys,
-      "type" : msg.type
-    });
-    info("sending update message to CDM: " + update);
-
-    ev.target.update(StringToArrayBuffer(update)).then(function() {
-      info("MediaKeySession update ok!");
-    }, bail("MediaKeySession update failed"));
-  }
-}
-
-function PlayFragmented(test, elem)
-{
-  var ms = new MediaSource();
-  elem.src = URL.createObjectURL(ms);
-
-  var sb;
-  var curFragment = 0;
-
-  function addNextFragment() {
-    if (curFragment >= test.fragments.length) {
-      ms.endOfStream();
-      elem.play();
-      return;
-    }
-
-    var fragmentFile = test.fragments[curFragment++];
-
-    var req = new XMLHttpRequest();
-    req.open("GET", fragmentFile);
-    req.responseType = "arraybuffer";
-
-    req.addEventListener("load", function() {
-      sb.appendBuffer(new Uint8Array(req.response));
-    });
-
-    info("fetching resource " + fragmentFile);
-    req.send(null);
-  }
-
-  ms.addEventListener("sourceopen", function () {
-    sb = ms.addSourceBuffer(test.type);
-    sb.addEventListener("updateend", addNextFragment);
-
-    addNextFragment();
-  });
-}
-
-function PlayTest(test, elem)
-{
-  if (test.fragments) {
-    PlayFragmented(test, elem);
-    return;
-  }
-
-  // This file isn't fragmented; set the media source normally.
-  elem.src = test.name;
-  elem.play();
-}
 
 function KeysChangeFunc(session, keys) {
   session.keyIdsReceived = [];
   for (var keyid in keys) {
     info("Set " + keyid + " to false in session.keyIdsReceived");
     session.keyIdsReceived[keyid] = false;
   }
   return function(ev) {
@@ -171,76 +31,66 @@ function KeysChangeFunc(session, keys) {
     }, bail("Failed to get keyIds"));
   }
 }
 
 function startTest(test, token)
 {
   manager.started(test._token);
 
-  var v = document.createElement("video");
+  var sessions = [];
+
+  var v = SetupEME(test, token,
+    {
+      onsessioncreated: function(session) {
+        sessions.push(session);
+        session.addEventListener("keyschange", KeysChangeFunc(session, test.keys), false);
+      }
+    }
+  );
+  
   var gotEncrypted = false;
   var gotPlaying = false;
 
   v.addEventListener("encrypted", function(ev) {
-    gotEncrypted = true;
-
-    info(token + " got encrypted event");
     ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
        token + " MediaKeys should support this keysystem");
-
-    MediaKeys.create(KEYSYSTEM_TYPE).then(function(mediaKeys) {
-      info(token + " created MediaKeys object ok");
-      mediaKeys.sessions = [];
-      return v.setMediaKeys(mediaKeys);
-    }, bail("failed to create MediaKeys object")).then(function() {
-      info(token + " set MediaKeys on <video> element ok");
-
-      ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
-         "MediaKeys should still support keysystem after CDM created...");
-
-      var session = v.mediaKeys.createSession(test.sessionType);
-      v.mediaKeys.sessions.push(session);
-      session.addEventListener("keyschange", KeysChangeFunc(session, test.keys), false);
-      session.addEventListener("message", UpdateSessionFunc(test));
-      session.generateRequest(ev.initDataType, ev.initData).then(function() {
-      }, bail(token + " Failed to initialise MediaKeySession"));
-
-    }, bail(token + " Failed to set MediaKeys on <video> element"));
+    gotEncrypted = true;
   });
 
   v.addEventListener("playing", function () { gotPlaying = true; });
 
   v.addEventListener("ended", function(ev) {
     ok(true, token + " got ended event");
     manager.finished(test._token);
 
     ok(gotEncrypted, token + " encrypted event should have fired");
     ok(gotPlaying, token + " playing event should have fired");
 
     ok(Math.abs(test.duration - v.duration) < 0.1,
        token + " Duration of video should be corrrect");
     ok(Math.abs(test.duration - v.currentTime) < 0.1,
        token + " Current time should be same as duration");
+
     // Verify all sessions had all keys went sent the to the CDM usable, and thus
     // that we received keyschange event(s).
-    var sessions = v.mediaKeys.sessions;
     is(sessions.length, 1, "should have 1 session");
     for (var i = 0; i < sessions.length; i++) {
       var session = sessions[i];
       ok(session.gotKeysChanged, "Should have received at least one keychange event");
       for (var kid in session.keyIdsReceived) {
         ok(session.keyIdsReceived[kid], "key with id " + kid + " was usable as expected");
       }
     }
-  });
+
+   });
 
   v.addEventListener("error", bail(token + " got error event"));
 
-  PlayTest(test, v);
+  LoadTest(test, v).then(function(){v.play();}, bail(token + " failed to load"));
 }
 
 function testIsTypeSupported()
 {
   var t = MediaKeys.isTypeSupported;
   const clearkey = "org.w3.clearkey";
   ok(!t("bogus", "bogon", "video/bogus"), "Invalid type.");
   ok(t(clearkey), "ClearKey supported.");