Bug 1214478 - Ensure MediaKeySession.close() does not store its promise twice. r=gerald, a=sylvestre
authorChris Pearce <cpearce@mozilla.com>
Wed, 14 Oct 2015 19:42:24 +1300
changeset 289545 a27cc6aa6e0d
parent 289544 28efbb818caa
child 289546 b09a797a251b
push id5178
push usercbook@mozilla.com
push date2015-10-15 09:17 +0000
treeherdermozilla-beta@b09a797a251b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald, sylvestre
bugs1214478
milestone42.0
Bug 1214478 - Ensure MediaKeySession.close() does not store its promise twice. r=gerald, a=sylvestre
dom/media/eme/MediaKeySession.cpp
dom/media/eme/MediaKeys.cpp
dom/media/test/eme.js
dom/media/test/test_eme_playback.html
--- 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);