author | Chris Pearce <cpearce@mozilla.com> |
Tue, 28 Oct 2014 13:21:11 +1300 | |
changeset 213051 | 34d86b491ac16a7322a66d3f6362761349bd510b |
parent 213050 | cc451b07de72c711aaaf464fa5638a62defaa45d |
child 213052 | 396575d789e430d815fd2ab1126c165db19d2629 |
push id | 27738 |
push user | cbook@mozilla.com |
push date | Thu, 30 Oct 2014 13:46:07 +0000 |
treeherder | mozilla-central@1aa1b23d799e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | edwin |
bugs | 1071482 |
milestone | 36.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
|
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.");