Bug 1214478 - Ensure MediaKeySession.close() does not store its promise twice. r=gerald, a=sylvestre
--- a/dom/media/eme/MediaKeySession.cpp
+++ b/dom/media/eme/MediaKeySession.cpp
@@ -310,17 +310,17 @@ MediaKeySession::Close(ErrorResult& aRv)
}
if (IsClosed() || !mKeys->GetCDMProxy()) {
EME_LOG("MediaKeySession[%p,'%s'] Close() already closed",
this, NS_ConvertUTF16toUTF8(mSessionId).get());
promise->MaybeResolve(JS::UndefinedHandleValue);
return promise.forget();
}
PromiseId pid = mKeys->StorePromise(promise);
- mKeys->GetCDMProxy()->CloseSession(mSessionId, mKeys->StorePromise(promise));
+ mKeys->GetCDMProxy()->CloseSession(mSessionId, pid);
EME_LOG("MediaKeySession[%p,'%s'] Close() sent to CDM, promiseId=%d",
this, NS_ConvertUTF16toUTF8(mSessionId).get(), pid);
return promise.forget();
}
void
--- a/dom/media/eme/MediaKeys.cpp
+++ b/dom/media/eme/MediaKeys.cpp
@@ -194,16 +194,23 @@ MediaKeys::StorePromise(DetailedPromise*
uint32_t id = sEMEPromiseCount++;
EME_LOG("MediaKeys[%p]::StorePromise() id=%d", this, id);
// Keep MediaKeys alive for the lifetime of its promises. Any still-pending
// promises are rejected in Shutdown().
AddRef();
+#ifdef DEBUG
+ // We should not have already stored this promise!
+ for (auto iter = mPromises.ConstIter(); !iter.Done(); iter.Next()) {
+ MOZ_ASSERT(iter.Data() != aPromise);
+ }
+#endif
+
mPromises.Put(id, aPromise);
return id;
}
already_AddRefed<DetailedPromise>
MediaKeys::RetrievePromise(PromiseId aId)
{
if (!mPromises.Contains(aId)) {
@@ -288,16 +295,17 @@ MediaKeys::ResolvePromise(PromiseId aId)
return;
}
mPendingSessions.Remove(aId);
mKeySessions.Put(session->GetSessionId(), session);
promise->MaybeResolve(session);
} else {
promise->MaybeResolve(JS::UndefinedHandleValue);
}
+ MOZ_ASSERT(!mPromises.Contains(aId));
}
already_AddRefed<DetailedPromise>
MediaKeys::Init(ErrorResult& aRv)
{
nsRefPtr<DetailedPromise> promise(MakePromise(aRv,
NS_LITERAL_CSTRING("MediaKeys::Init()")));
if (aRv.Failed()) {
--- a/dom/media/test/eme.js
+++ b/dom/media/test/eme.js
@@ -272,16 +272,29 @@ function LoadTestWithManagedLoadToken(te
manager.finished(token + "_load");
});
}
function SetupEME(test, token, params)
{
var v = document.createElement("video");
v.crossOrigin = test.crossOrigin || false;
+ 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.parentNode.removeChild(v);
+ }
+ 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",
].forEach(function (e) {
v.addEventListener(e, function(event) {
Log(token, "" + e);
@@ -306,16 +319,17 @@ function SetupEME(test, token, params)
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);
--- a/dom/media/test/test_eme_playback.html
+++ b/dom/media/test/test_eme_playback.html
@@ -90,17 +90,17 @@ function startTest(test, token)
Log(token, "session[" + session.sessionId + "] key " + kid + " = " + (session.keyIdsReceived[kid] ? "true" : "false"));
if (session.keyIdsReceived[kid]) { keyIdsReceived[kid] = true; }
}
}
for (var kid in keyIdsReceived) {
ok(keyIdsReceived[kid], TimeStamp(token) + " key with id " + kid + " was usable as expected");
}
- manager.finished(token);
+ v.closeSessions().then(() => manager.finished(token));
});
LoadTest(test, v, token)
.then(function() {
v.play();
}).catch(function() {
ok(false, token + " failed to load");
manager.finished(token);