Bug 1310936- Provide a map to get pending MediaKeySession by promise Id correctly.
MozReview-Commit-ID: 34BL4GYoC1A
--- a/dom/media/eme/MediaKeySession.cpp
+++ b/dom/media/eme/MediaKeySession.cpp
@@ -64,17 +64,17 @@ MediaKeySession::MediaKeySession(JSConte
, mCDMVersion(aCDMVersion)
, mSessionType(aSessionType)
, mToken(sMediaKeySessionNum++)
, mIsClosed(false)
, mUninitialized(true)
, mKeyStatusMap(new MediaKeyStatusMap(aParent))
, mExpiration(JS::GenericNaN())
{
- EME_LOG("MediaKeySession[%p,''] session Id set", this);
+ EME_LOG("MediaKeySession[%p,''] ctor", this);
MOZ_ASSERT(aParent);
if (aRv.Failed()) {
return;
}
mClosed = MakePromise(aRv, NS_LITERAL_CSTRING("MediaKeys.createSession"));
}
@@ -320,16 +320,17 @@ MediaKeySession::GenerateRequest(const n
Telemetry::Accumulate(Telemetry::VIDEO_CDM_GENERATE_REQUEST_CALLED,
ToCDMTypeTelemetryEnum(mKeySystem));
// Convert initData to base64 for easier logging.
// Note: CreateSession() Move()s the data out of the array, so we have
// to copy it here.
nsAutoCString base64InitData(ToBase64(data));
PromiseId pid = mKeys->StorePromise(promise);
+ mKeys->ConnectPendingPromiseIdWithToken(pid, Token());
mKeys->GetCDMProxy()->CreateSession(Token(),
mSessionType,
pid,
aInitDataType, data);
EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() sent, "
"promiseId=%d initData(base64)='%s' initDataType='%s'",
this,
@@ -385,16 +386,17 @@ MediaKeySession::Load(const nsAString& a
// session from its owning MediaKey's set of sessions awaiting a sessionId.
RefPtr<MediaKeySession> session(mKeys->GetPendingSession(Token()));
MOZ_ASSERT(session == this, "Session should be awaiting id on its own token");
// Associate with the known sessionId.
SetSessionId(aSessionId);
PromiseId pid = mKeys->StorePromise(promise);
+ mKeys->ConnectPendingPromiseIdWithToken(pid, Token());
mKeys->GetCDMProxy()->LoadSession(pid, aSessionId);
EME_LOG("MediaKeySession[%p,'%s'] Load() sent to CDM, promiseId=%d",
this, NS_ConvertUTF16toUTF8(mSessionId).get(), pid);
return promise.forget();
}
--- a/dom/media/eme/MediaKeys.cpp
+++ b/dom/media/eme/MediaKeys.cpp
@@ -191,16 +191,26 @@ MediaKeys::StorePromise(DetailedPromise*
MOZ_ASSERT(iter.Data() != aPromise);
}
#endif
mPromises.Put(id, aPromise);
return id;
}
+void
+MediaKeys::ConnectPendingPromiseIdWithToken(PromiseId aId, uint32_t aToken)
+{
+ // Should only be called from MediaKeySession::GenerateRequest and
+ // MediaKeySession::Load.
+ mPromiseIdToken.Put(aId, aToken);
+ EME_LOG("MediaKeys[%p]::ConnectPendingPromiseIdWithToken() id=%u => token(%u)",
+ this, aId, aToken);
+}
+
already_AddRefed<DetailedPromise>
MediaKeys::RetrievePromise(PromiseId aId)
{
if (!mPromises.Contains(aId)) {
NS_WARNING(nsPrintfCString("Tried to retrieve a non-existent promise id=%d", aId).get());
return nullptr;
}
RefPtr<DetailedPromise> promise;
@@ -214,22 +224,26 @@ MediaKeys::RejectPromise(PromiseId aId,
const nsCString& aReason)
{
EME_LOG("MediaKeys[%p]::RejectPromise(%d, 0x%x)", this, aId, aExceptionCode);
RefPtr<DetailedPromise> promise(RetrievePromise(aId));
if (!promise) {
return;
}
- if (mPendingSessions.Contains(aId)) {
- // This promise could be a createSession or loadSession promise,
- // so we might have a pending session waiting to be resolved into
- // the promise on success. We've been directed to reject to promise,
- // so we can throw away the corresponding session object.
- mPendingSessions.Remove(aId);
+
+ // This promise could be a createSession or loadSession promise,
+ // so we might have a pending session waiting to be resolved into
+ // the promise on success. We've been directed to reject to promise,
+ // so we can throw away the corresponding session object.
+ uint32_t token = 0;
+ if (mPromiseIdToken.Get(aId, &token)) {
+ MOZ_ASSERT(mPendingSessions.Contains(token));
+ mPendingSessions.Remove(token);
+ mPromiseIdToken.Remove(aId);
}
MOZ_ASSERT(NS_FAILED(aExceptionCode));
promise->MaybeReject(aExceptionCode, aReason);
if (mCreatePromiseId == aId) {
// Note: This will probably destroy the MediaKeys object!
Release();
@@ -259,39 +273,46 @@ MediaKeys::OnSessionIdReady(MediaKeySess
}
void
MediaKeys::ResolvePromise(PromiseId aId)
{
EME_LOG("MediaKeys[%p]::ResolvePromise(%d)", this, aId);
RefPtr<DetailedPromise> promise(RetrievePromise(aId));
+ MOZ_ASSERT(!mPromises.Contains(aId));
if (!promise) {
return;
}
- if (mPendingSessions.Contains(aId)) {
- // We should only resolve LoadSession calls via this path,
- // not CreateSession() promises.
- RefPtr<MediaKeySession> session;
- if (!mPendingSessions.Get(aId, getter_AddRefs(session)) ||
- !session ||
- session->GetSessionId().IsEmpty()) {
- NS_WARNING("Received activation for non-existent session!");
- promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR,
- NS_LITERAL_CSTRING("CDM LoadSession() returned a different session ID than requested"));
- mPendingSessions.Remove(aId);
- return;
- }
- mPendingSessions.Remove(aId);
- mKeySessions.Put(session->GetSessionId(), session);
- promise->MaybeResolve(session);
- } else {
+
+ uint32_t token = 0;
+ if (!mPromiseIdToken.Get(aId, &token)) {
+ promise->MaybeResolveWithUndefined();
+ return;
+ } else if (!mPendingSessions.Contains(token)) {
+ // Pending session for CreateSession() should be removed when sessionId
+ // is ready.
promise->MaybeResolveWithUndefined();
+ mPromiseIdToken.Remove(aId);
+ return;
}
- MOZ_ASSERT(!mPromises.Contains(aId));
+ mPromiseIdToken.Remove(aId);
+
+ // We should only resolve LoadSession calls via this path,
+ // not CreateSession() promises.
+ RefPtr<MediaKeySession> session;
+ mPendingSessions.Remove(token, getter_AddRefs(session));
+ if (!session || session->GetSessionId().IsEmpty()) {
+ NS_WARNING("Received activation for non-existent session!");
+ promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR,
+ NS_LITERAL_CSTRING("CDM LoadSession() returned a different session ID than requested"));
+ return;
+ }
+ mKeySessions.Put(session->GetSessionId(), session);
+ promise->MaybeResolve(session);
}
class MediaKeysGMPCrashHelper : public GMPCrashHelper
{
public:
explicit MediaKeysGMPCrashHelper(MediaKeys* aMediaKeys)
: mMediaKeys(aMediaKeys)
{
--- a/dom/media/eme/MediaKeys.h
+++ b/dom/media/eme/MediaKeys.h
@@ -28,16 +28,17 @@ namespace dom {
class ArrayBufferViewOrArrayBuffer;
class MediaKeySession;
class HTMLMediaElement;
typedef nsRefPtrHashtable<nsStringHashKey, MediaKeySession> KeySessionHashMap;
typedef nsRefPtrHashtable<nsUint32HashKey, dom::DetailedPromise> PromiseHashMap;
typedef nsRefPtrHashtable<nsUint32HashKey, MediaKeySession> PendingKeySessionsHashMap;
+typedef nsDataHashtable<nsUint32HashKey, uint32_t> PendingPromiseIdTokenHashMap;
typedef uint32_t PromiseId;
// This class is used on the main thread only.
// Note: its addref/release is not (and can't be) thread safe!
class MediaKeys final : public nsISupports,
public nsWrapperCache,
public SupportsWeakPtr<MediaKeys>
{
@@ -102,16 +103,21 @@ public:
// Makes a new promise, or nullptr on failure.
already_AddRefed<DetailedPromise> MakePromise(ErrorResult& aRv,
const nsACString& aName);
// Stores promise in mPromises, returning an ID that can be used to retrieve
// it later. The ID is passed to the CDM, so that it can signal specific
// promises to be resolved.
PromiseId StorePromise(DetailedPromise* aPromise);
+ // Stores a map for promise id and session token, and it will be used to
+ // remove the pending sessions by promise id while creating/loading various
+ // sessions in the same time.
+ void ConnectPendingPromiseIdWithToken(PromiseId aId, uint32_t aToken);
+
// Reject promise with DOMException corresponding to aExceptionCode.
void RejectPromise(PromiseId aId, nsresult aExceptionCode,
const nsCString& aReason);
// Resolves promise with "undefined".
void ResolvePromise(PromiseId aId);
const nsCString& GetNodeId() const;
@@ -146,14 +152,16 @@ private:
PendingKeySessionsHashMap mPendingSessions;
PromiseId mCreatePromiseId;
RefPtr<nsIPrincipal> mPrincipal;
RefPtr<nsIPrincipal> mTopLevelPrincipal;
const bool mDistinctiveIdentifierRequired;
const bool mPersistentStateRequired;
+
+ PendingPromiseIdTokenHashMap mPromiseIdToken;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_mediakeys_h__