Bug 1145011 - Add test for waitingforkey. r=jya
MozReview-Commit-ID: LKlDd4wkRSE
--- a/dom/media/test/eme.js
+++ b/dom/media/test/eme.js
@@ -244,24 +244,26 @@ function LoadTest(test, elem, token, loa
Log(token, "sourceopen again?");
return;
}
firstOpen = false;
Log(token, "sourceopen");
return Promise.all(test.tracks.map(function(track) {
return AppendTrack(test, ms, track, token, loadParams);
- })).then(function(){
+ })).then(function() {
if (loadParams && loadParams.noEndOfStream) {
Log(token, "Tracks loaded");
} else {
Log(token, "Tracks loaded, calling MediaSource.endOfStream()");
ms.endOfStream();
}
resolve();
+ }).catch(function() {
+ Log(token, "error while loading tracks");
});
})
});
}
// Same as LoadTest, but manage a token+"_load" start&finished.
// Also finish main token if loading fails.
function LoadTestWithManagedLoadToken(test, elem, manager, token, loadParams)
@@ -294,38 +296,53 @@ function SetupEME(test, token, params)
v.onerror = null;
v.src = null;
});
};
// Log events dispatched to make debugging easier...
[ "canplay", "canplaythrough", "ended", "error", "loadeddata",
"loadedmetadata", "loadstart", "pause", "play", "playing", "progress",
- "stalled", "suspend", "waiting",
+ "stalled", "suspend", "waiting", "waitingforkey",
].forEach(function (e) {
v.addEventListener(e, function(event) {
Log(token, "" + e);
}, false);
});
// 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
+ // [...]: 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)));
+ }
+ }
+
function processInitDataQueue()
{
if (initDataQueue === null) { return; }
- if (initDataQueue.length === 0) { initDataQueue = null; return; }
+ // If we're processed all our init data null the queue to indicate encrypted event handled.
+ if (initDataQueue.length === 0) {
+ initDataQueue = null;
+ 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);
}
@@ -351,24 +368,29 @@ function SetupEME(test, token, params)
});
}
function streamType(type) {
var x = test.tracks.find(o => o.name == type);
return x ? x.type : undefined;
}
- // All 'initDataType's should be the same.
- // null indicates no 'encrypted' event received yet.
- var initDataType = null;
+ // 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;
+ }
+
+ // Is this the first piece of init data we're processing?
+ var firstInitData = true;
v.addEventListener("encrypted", function(ev) {
- if (initDataType === null) {
+ if (firstInitData) {
Log(token, "got first encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + "), setup session");
- initDataType = ev.initDataType;
- initDataQueue.push(ev);
+ 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();
})
@@ -395,30 +417,33 @@ function SetupEME(test, token, params)
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");
- processInitDataQueue();
+ if (params && params.onMediaKeysSet) {
+ params.onMediaKeysSet();
+ }
+ if (!(params && params.delaySessions)) {
+ processInitDataQueue();
+ }
})
} else {
- if (ev.initDataType !== initDataType) {
- return bail(token + ": encrypted(" + ev.initDataType + ", " +
- StringToHex(ArrayBufferToString(ev.initData)) + ")")
- ("expected " + initDataType);
- }
- if (initDataQueue !== null) {
+ 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");
- initDataQueue.push(ev);
+ pushInitData(ev);
} else {
Log(token, "got encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") event, update session now");
- initDataQueue = [ev];
+ pushInitData(ev);
processInitDataQueue();
}
}
});
return v;
}
function SetupEMEPref(callback) {
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -664,16 +664,18 @@ skip-if = toolkit == 'android' # bug 114
tags=msg capturestream
skip-if = toolkit == 'android' || toolkit == 'gonk' # android: bug 1149374; gonk: bug 1193351
[test_eme_stream_capture_blocked_case2.html]
tags=msg capturestream
skip-if = toolkit == 'android' || toolkit == 'gonk' # android: bug 1149374; gonk: bug 1193351
[test_eme_stream_capture_blocked_case3.html]
tags=msg capturestream
skip-if = toolkit == 'android' || toolkit == 'gonk' # android: bug 1149374; gonk: bug 1193351
+[test_eme_waitingforkey.html]
+skip-if = toolkit == 'android' || toolkit == 'gonk' # android: bug 1149374; gonk: bug 1193351
[test_empty_resource.html]
[test_error_in_video_document.html]
[test_error_on_404.html]
[test_fastSeek.html]
[test_fastSeek-forwards.html]
[test_gmp_playback.html]
skip-if = (os != 'win' || os_version == '5.1') # Only gmp-clearkey on Windows Vista and later decodes
[test_imagecapture.html]
new file mode 100644
--- /dev/null
+++ b/dom/media/test/test_eme_waitingforkey.html
@@ -0,0 +1,111 @@
+<!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="http://test1.mochi.test:8888/tests/dom/media/test/eme.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function startTest(test, token)
+{
+ // Test if the appropriate preconditions are met such that we can start
+ // prcoessing delayed sessions.
+ function TestIfDoneDelaying()
+ {
+ var got = "Got:";
+ if (loaded) { got += " loaded,"; }
+ got += " " + gotEncrypted + "/" + test.sessionCount + " sessions,";
+ got += " " + gotWaitingForKey + " waiting for key events"
+ if (loaded && gotEncrypted == test.sessionCount && gotWaitingForKey > 0) {
+ Log(token, got + " -> Update sessions with keys");
+ params.ProcessSessions();
+ } else {
+ Log(token, got + " -> Wait for more...");
+ }
+ }
+
+ manager.started(token);
+
+ var updatedSessionsCount = 0;
+ var loaded = false;
+
+ var params = {
+ // params will be populated with a ProcessSessions() callback, that can be
+ // called to process delayed sessions.
+ delaySessions: true,
+ // Function to be called once we start processing and updating sessions.
+ // This should only be called once the preconditions in TestIfDoneDealying
+ // are met.
+ onsessionupdated: function(session) {
+ updatedSessionsCount += 1;
+ if (updatedSessionsCount == test.sessionCount) {
+ info(TimeStamp(token) + " Updated all sessions, loading complete -> Play");
+ v.play();
+ } else {
+ info(TimeStamp(token) + " Updated " + updatedSessionsCount + "/" + test.sessionCount + " sessions so far");
+ }
+ },
+ };
+ var v = SetupEME(test, token, params);
+
+ document.body.appendChild(v);
+
+ var gotEncrypted = 0;
+ var gotWaitingForKey = 0;
+
+ v.addEventListener("encrypted", function() {
+ gotEncrypted += 1;
+ TestIfDoneDelaying();
+ });
+
+ v.addEventListener("waitingforkey", function() {
+ gotWaitingForKey += 1;
+ TestIfDoneDelaying()
+ });
+
+ v.addEventListener("loadedmetadata", function() {
+ ok(SpecialPowers.do_lookupGetter(v, "isEncrypted").apply(v),
+ TimeStamp(token) + " isEncrypted should be true");
+ is(v.isEncrypted, undefined, "isEncrypted should not be accessible from content");
+ });
+
+ v.addEventListener("ended", function() {
+ ok(true, TimeStamp(token) + " got ended event");
+ // We expect only one waitingForKey as we delay until all sessions are ready.
+ // I.e. one waitingForKey should be fired, after which, we process all sessions,
+ // so it should not be possible to be blocked by a key after that point.
+ ok(gotWaitingForKey == 1, "Expected number 1 wait, got: " + gotWaitingForKey);
+
+ v.closeSessions().then(() => manager.finished(token));
+ });
+
+ LoadTest(test, v, token)
+ .then(function() {
+ loaded = true;
+ TestIfDoneDelaying();
+ }).catch(function() {
+ ok(false, token + " failed to load");
+ manager.finished(token);
+ });
+}
+
+function beginTest() {
+ manager.runTests(gEMETests, startTest);
+}
+
+if (!IsMacOSSnowLeopardOrEarlier()) {
+ SimpleTest.waitForExplicitFinish();
+ SetupEMEPref(beginTest);
+} else {
+ todo(false, "Test disabled on this platform.");
+}
+</script>
+</pre>
+</body>
+</html>