Bug 1290830 - [Part2] Remove the GMP types using genral types instead. r?cpearce draft
authorJames Cheng <jacheng@mozilla.com>
Tue, 02 Aug 2016 15:05:21 +0800
changeset 404341 7df6428f9f9020205c9952f209f9ff6ac2fc6512
parent 404340 bb5de0af6927b5b1ecdbab59aaeeb737e41a8a00
child 529159 3ffb56f238d5ac376839465e036c807a944d1d82
push id27183
push userbmo:jacheng@mozilla.com
push dateTue, 23 Aug 2016 08:40:42 +0000
reviewerscpearce
bugs1290830
milestone51.0a1
Bug 1290830 - [Part2] Remove the GMP types using genral types instead. r?cpearce MozReview-Commit-ID: 3EKwTNPddI1
dom/media/eme/CDMCaps.cpp
dom/media/eme/CDMCaps.h
dom/media/eme/CDMProxy.h
dom/media/eme/DecryptorProxyCallback.h
dom/media/eme/MediaKeySession.cpp
dom/media/eme/MediaKeyStatusMap.cpp
dom/media/gmp/GMPCDMCallbackProxy.cpp
dom/media/gmp/GMPCDMCallbackProxy.h
dom/media/gmp/GMPDecryptorChild.cpp
dom/media/gmp/GMPDecryptorParent.cpp
dom/media/gmp/GMPDecryptorParent.h
dom/media/gmp/PGMPDecryptor.ipdl
dom/media/gtest/TestGMPCrossOrigin.cpp
--- a/dom/media/eme/CDMCaps.cpp
+++ b/dom/media/eme/CDMCaps.cpp
@@ -38,24 +38,25 @@ CDMCaps::AutoLock::AutoLock(CDMCaps& aIn
   mData.Lock();
 }
 
 CDMCaps::AutoLock::~AutoLock()
 {
   mData.Unlock();
 }
 
-// Keys with kGMPUsable, kGMPOutputDownscaled, or kGMPOutputRestricted status
-// can be used by the CDM to decrypt or decrypt-and-decode samples.
+// Keys with MediaKeyStatus::Usable, MediaKeyStatus::Output_downscaled,
+// or MediaKeyStatus::Output_restricted status can be used by the CDM
+// to decrypt or decrypt-and-decode samples.
 static bool
-IsUsableStatus(GMPMediaKeyStatus aStatus)
+IsUsableStatus(dom::MediaKeyStatus aStatus)
 {
-  return aStatus == kGMPUsable ||
-         aStatus == kGMPOutputRestricted ||
-         aStatus == kGMPOutputDownscaled;
+  return aStatus == dom::MediaKeyStatus::Usable ||
+         aStatus == dom::MediaKeyStatus::Output_restricted ||
+         aStatus == dom::MediaKeyStatus::Output_downscaled;
 }
 
 bool
 CDMCaps::AutoLock::IsKeyUsable(const CencKeyId& aKeyId)
 {
   mData.mMonitor.AssertCurrentThreadOwns();
   for (const KeyStatus& keyStatus : mData.mKeyStatuses) {
     if (keyStatus.mId == aKeyId) {
@@ -63,48 +64,51 @@ CDMCaps::AutoLock::IsKeyUsable(const Cen
     }
   }
   return false;
 }
 
 bool
 CDMCaps::AutoLock::SetKeyStatus(const CencKeyId& aKeyId,
                                 const nsString& aSessionId,
-                                GMPMediaKeyStatus aStatus)
+                                const dom::Optional<dom::MediaKeyStatus>& aStatus)
 {
   mData.mMonitor.AssertCurrentThreadOwns();
-  KeyStatus key(aKeyId, aSessionId, aStatus);
 
-  if (aStatus == kGMPUnknown) {
+  if (!aStatus.WasPassed()) {
+    // Called from ForgetKeyStatus.
     // Return true if the element is found to notify key changes.
-    return mData.mKeyStatuses.RemoveElement(key);
+    return mData.mKeyStatuses.RemoveElement(KeyStatus(aKeyId,
+                                                      aSessionId,
+                                                      dom::MediaKeyStatus::Internal_error));
   }
 
+  KeyStatus key(aKeyId, aSessionId, aStatus.Value());
   auto index = mData.mKeyStatuses.IndexOf(key);
   if (index != mData.mKeyStatuses.NoIndex) {
-    if (mData.mKeyStatuses[index].mStatus == aStatus) {
+    if (mData.mKeyStatuses[index].mStatus == aStatus.Value()) {
       // No change.
       return false;
     }
     auto oldStatus = mData.mKeyStatuses[index].mStatus;
-    mData.mKeyStatuses[index].mStatus = aStatus;
+    mData.mKeyStatuses[index].mStatus = aStatus.Value();
     // The old key status was one for which we can decrypt media. We don't
     // need to do the "notify usable" step below, as it should be impossible
     // for us to have anything waiting on this key to become usable, since it
     // was already usable.
     if (IsUsableStatus(oldStatus)) {
       return true;
     }
   } else {
     mData.mKeyStatuses.AppendElement(key);
   }
 
   // Only call NotifyUsable() for a key when we are going from non-usable
   // to usable state.
-  if (!IsUsableStatus(aStatus)) {
+  if (!IsUsableStatus(aStatus.Value())) {
     return true;
   }
 
   auto& waiters = mData.mWaitForKeys;
   size_t i = 0;
   while (i < waiters.Length()) {
     auto& w = waiters[i];
     if (w.mKeyId == aKeyId) {
@@ -150,15 +154,17 @@ CDMCaps::AutoLock::GetSessionIdsForKeyId
 }
 
 bool
 CDMCaps::AutoLock::RemoveKeysForSession(const nsString& aSessionId)
 {
   bool changed = false;
   nsTArray<KeyStatus> statuses;
   GetKeyStatusesForSession(aSessionId, statuses);
-  for (const KeyStatus& keyStatus : statuses) {
-    changed |= SetKeyStatus(keyStatus.mId, aSessionId, kGMPUnknown);
+  for (const KeyStatus& status : statuses) {
+    changed |= SetKeyStatus(status.mId,
+                            aSessionId,
+                            dom::Optional<dom::MediaKeyStatus>());
   }
   return changed;
 }
 
 } // namespace mozilla
--- a/dom/media/eme/CDMCaps.h
+++ b/dom/media/eme/CDMCaps.h
@@ -2,68 +2,73 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef CDMCaps_h_
 #define CDMCaps_h_
 
-#include "nsString.h"
-#include "mozilla/Monitor.h"
+#include "gmp-decryption.h"
 #include "nsIThread.h"
 #include "nsTArray.h"
-#include "mozilla/Attributes.h"
+#include "nsString.h"
 #include "SamplesWaitingForKey.h"
-#include "gmp-decryption.h"
+
+#include "mozilla/Monitor.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/dom/MediaKeyStatusMapBinding.h" // For MediaKeyStatus
+#include "mozilla/dom/BindingDeclarations.h" // For Optional
 
 namespace mozilla {
 
 // CDM capabilities; what keys a CDMProxy can use.
 // Must be locked to access state.
 class CDMCaps {
 public:
   CDMCaps();
   ~CDMCaps();
 
   struct KeyStatus {
     KeyStatus(const CencKeyId& aId,
               const nsString& aSessionId,
-              GMPMediaKeyStatus aStatus)
+              dom::MediaKeyStatus aStatus)
       : mId(aId)
       , mSessionId(aSessionId)
       , mStatus(aStatus)
     {}
     KeyStatus(const KeyStatus& aOther)
       : mId(aOther.mId)
       , mSessionId(aOther.mSessionId)
       , mStatus(aOther.mStatus)
     {}
     bool operator==(const KeyStatus& aOther) const {
       return mId == aOther.mId &&
              mSessionId == aOther.mSessionId;
     };
 
     CencKeyId mId;
     nsString mSessionId;
-    GMPMediaKeyStatus mStatus;
+    dom::MediaKeyStatus mStatus;
   };
 
   // Locks the CDMCaps. It must be locked to access its shared state.
   // Threadsafe when locked.
   class MOZ_STACK_CLASS AutoLock {
   public:
     explicit AutoLock(CDMCaps& aKeyCaps);
     ~AutoLock();
 
     bool IsKeyUsable(const CencKeyId& aKeyId);
 
     // Returns true if key status changed,
     // i.e. the key status changed from usable to expired.
-    bool SetKeyStatus(const CencKeyId& aKeyId, const nsString& aSessionId, GMPMediaKeyStatus aStatus);
+    bool SetKeyStatus(const CencKeyId& aKeyId,
+                      const nsString& aSessionId,
+                      const dom::Optional<dom::MediaKeyStatus>& aStatus);
 
     void GetKeyStatusesForSession(const nsAString& aSessionId,
                                   nsTArray<KeyStatus>& aOutKeyStatuses);
 
     void GetSessionIdsForKeyId(const CencKeyId& aKeyId,
                                nsTArray<nsCString>& aOutSessionIds);
 
     // Ensures all keys for a session are marked as 'unknown', i.e. removed.
--- a/dom/media/eme/CDMProxy.h
+++ b/dom/media/eme/CDMProxy.h
@@ -29,16 +29,18 @@ struct DecryptResult {
   DecryptResult(DecryptStatus aStatus, MediaRawData* aSample)
     : mStatus(aStatus)
     , mSample(aSample)
   {}
   DecryptStatus mStatus;
   RefPtr<MediaRawData> mSample;
 };
 
+typedef int64_t UnixTime;
+
 // Proxies calls CDM, and proxies calls back.
 // Note: Promises are passed in via a PromiseId, so that the ID can be
 // passed via IPC to the CDM, which can then signal when to reject or
 // resolve the promise using its PromiseId.
 class CDMProxy {
 protected:
   typedef dom::PromiseId PromiseId;
   typedef dom::MediaKeySessionType MediaKeySessionType;
@@ -137,17 +139,17 @@ public:
 
   // Main thread only.
   virtual void OnSessionMessage(const nsAString& aSessionId,
                                 dom::MediaKeyMessageType aMessageType,
                                 nsTArray<uint8_t>& aMessage) = 0;
 
   // Main thread only.
   virtual void OnExpirationChange(const nsAString& aSessionId,
-                                  int64_t aExpiryTime) = 0;
+                                  UnixTime aExpiryTime) = 0;
 
   // Main thread only.
   virtual void OnSessionClosed(const nsAString& aSessionId) = 0;
 
   // Main thread only.
   virtual void OnSessionError(const nsAString& aSessionId,
                               nsresult aException,
                               uint32_t aSystemCode,
--- a/dom/media/eme/DecryptorProxyCallback.h
+++ b/dom/media/eme/DecryptorProxyCallback.h
@@ -1,48 +1,56 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef DecryptorProxyCallback_h_
 #define DecryptorProxyCallback_h_
 
+#include "mozilla/dom/MediaKeyStatusMapBinding.h" // For MediaKeyStatus
+#include "mozilla/dom/MediaKeyMessageEventBinding.h" // For MediaKeyMessageType
+#include "mozilla/CDMProxy.h"
+
 class DecryptorProxyCallback {
 public:
+
   virtual ~DecryptorProxyCallback() {}
 
   virtual void SetSessionId(uint32_t aCreateSessionId,
                             const nsCString& aSessionId) = 0;
 
   virtual void ResolveLoadSessionPromise(uint32_t aPromiseId,
                                          bool aSuccess) = 0;
 
   virtual void ResolvePromise(uint32_t aPromiseId) = 0;
 
   virtual void RejectPromise(uint32_t aPromiseId,
                              nsresult aException,
                              const nsCString& aSessionId) = 0;
 
   virtual void SessionMessage(const nsCString& aSessionId,
-                              GMPSessionMessageType aMessageType,
+                              mozilla::dom::MediaKeyMessageType aMessageType,
                               const nsTArray<uint8_t>& aMessage) = 0;
 
   virtual void ExpirationChange(const nsCString& aSessionId,
-                                GMPTimestamp aExpiryTime) = 0;
+                                mozilla::UnixTime aExpiryTime) = 0;
 
   virtual void SessionClosed(const nsCString& aSessionId) = 0;
 
   virtual void SessionError(const nsCString& aSessionId,
                             nsresult aException,
                             uint32_t aSystemCode,
                             const nsCString& aMessage) = 0;
 
   virtual void KeyStatusChanged(const nsCString& aSessionId,
                                 const nsTArray<uint8_t>& aKeyId,
-                                GMPMediaKeyStatus aStatus) = 0;
+                                mozilla::dom::MediaKeyStatus aStatus) = 0;
+
+  virtual void ForgetKeyStatus(const nsCString& aSessionId,
+                               const nsTArray<uint8_t>& aKeyId) = 0;
 
   virtual void Decrypted(uint32_t aId,
-                         GMPErr aResult,
+                         mozilla::DecryptStatus aResult,
                          const nsTArray<uint8_t>& aDecryptedData) = 0;
 };
 
 #endif
\ No newline at end of file
--- a/dom/media/eme/MediaKeySession.cpp
+++ b/dom/media/eme/MediaKeySession.cpp
@@ -139,19 +139,20 @@ MediaKeySession::UpdateKeyStatusMap()
   }
 
   mKeyStatusMap->Update(keyStatuses);
 
   if (EME_LOG_ENABLED()) {
     nsAutoCString message(
       nsPrintfCString("MediaKeySession[%p,'%s'] key statuses change {",
                       this, NS_ConvertUTF16toUTF8(mSessionId).get()));
+    using IntegerType = typename std::underlying_type<MediaKeyStatus>::type;
     for (const CDMCaps::KeyStatus& status : keyStatuses) {
       message.Append(nsPrintfCString(" (%s,%s)", ToBase64(status.mId).get(),
-        MediaKeyStatusValues::strings[status.mStatus].value));
+        MediaKeyStatusValues::strings[static_cast<IntegerType>(status.mStatus)].value));
     }
     message.Append(" }");
     EME_LOG(message.get());
   }
 }
 
 MediaKeyStatusMap*
 MediaKeySession::KeyStatuses() const
--- a/dom/media/eme/MediaKeyStatusMap.cpp
+++ b/dom/media/eme/MediaKeyStatusMap.cpp
@@ -103,33 +103,19 @@ MediaKeyStatusMap::GetValueAtIndex(uint3
 }
 
 uint32_t
 MediaKeyStatusMap::Size() const
 {
   return mStatuses.Length();
 }
 
-static MediaKeyStatus
-ToMediaKeyStatus(GMPMediaKeyStatus aStatus) {
-  switch (aStatus) {
-    case kGMPUsable: return MediaKeyStatus::Usable;
-    case kGMPExpired: return MediaKeyStatus::Expired;
-    case kGMPOutputDownscaled: return MediaKeyStatus::Output_downscaled;
-    case kGMPOutputRestricted: return MediaKeyStatus::Output_restricted;
-    case kGMPInternalError: return MediaKeyStatus::Internal_error;
-    case kGMPReleased: return MediaKeyStatus::Released;
-    case kGMPStatusPending: return MediaKeyStatus::Status_pending;
-    default: return MediaKeyStatus::Internal_error;
-  }
-}
-
 void
 MediaKeyStatusMap::Update(const nsTArray<CDMCaps::KeyStatus>& aKeys)
 {
   mStatuses.Clear();
   for (const auto& key : aKeys) {
-    mStatuses.InsertElementSorted(KeyStatus(key.mId, ToMediaKeyStatus(key.mStatus)));
+    mStatuses.InsertElementSorted(KeyStatus(key.mId, key.mStatus));
   }
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/media/gmp/GMPCDMCallbackProxy.cpp
+++ b/dom/media/gmp/GMPCDMCallbackProxy.cpp
@@ -133,55 +133,44 @@ GMPCDMCallbackProxy::RejectPromise(uint3
   nsCOMPtr<nsIRunnable> task;
   task = new RejectPromiseTask(mProxy,
                                aPromiseId,
                                aException,
                                aMessage);
   NS_DispatchToMainThread(task);
 }
 
-static dom::MediaKeyMessageType
-ToMediaKeyMessageType(GMPSessionMessageType aMessageType) {
-  switch (aMessageType) {
-    case kGMPLicenseRequest: return dom::MediaKeyMessageType::License_request;
-    case kGMPLicenseRenewal: return dom::MediaKeyMessageType::License_renewal;
-    case kGMPLicenseRelease: return dom::MediaKeyMessageType::License_release;
-    case kGMPIndividualizationRequest: return dom::MediaKeyMessageType::Individualization_request;
-    default: return dom::MediaKeyMessageType::License_request;
-  };
-};
-
 class SessionMessageTask : public Runnable {
 public:
   SessionMessageTask(CDMProxy* aProxy,
                      const nsCString& aSessionId,
-                     GMPSessionMessageType aMessageType,
+                     dom::MediaKeyMessageType aMessageType,
                      const nsTArray<uint8_t>& aMessage)
     : mProxy(aProxy)
     , mSid(NS_ConvertUTF8toUTF16(aSessionId))
     , mMsgType(aMessageType)
   {
     mMsg.AppendElements(aMessage);
   }
 
   NS_IMETHOD Run() override {
-    mProxy->OnSessionMessage(mSid, ToMediaKeyMessageType(mMsgType), mMsg);
+    mProxy->OnSessionMessage(mSid, mMsgType, mMsg);
     return NS_OK;
   }
 
   RefPtr<CDMProxy> mProxy;
   dom::PromiseId mPid;
   nsString mSid;
-  GMPSessionMessageType mMsgType;
+  dom::MediaKeyMessageType mMsgType;
   nsTArray<uint8_t> mMsg;
 };
 
 void
 GMPCDMCallbackProxy::SessionMessage(const nsCString& aSessionId,
-                                    GMPSessionMessageType aMessageType,
+                                    dom::MediaKeyMessageType aMessageType,
                                     const nsTArray<uint8_t>& aMessage)
 {
   MOZ_ASSERT(mProxy->IsOnOwnerThread());
 
   nsCOMPtr<nsIRunnable> task;
   task = new SessionMessageTask(mProxy,
                                 aSessionId,
                                 aMessageType,
@@ -289,55 +278,65 @@ GMPCDMCallbackProxy::SessionError(const 
                               aSystemCode,
                               aMessage);
   NS_DispatchToMainThread(task);
 }
 
 void
 GMPCDMCallbackProxy::KeyStatusChanged(const nsCString& aSessionId,
                                       const nsTArray<uint8_t>& aKeyId,
-                                      GMPMediaKeyStatus aStatus)
+                                      dom::MediaKeyStatus aStatus)
 {
   MOZ_ASSERT(mProxy->IsOnOwnerThread());
 
+  KeyStatusChangedInternal(aSessionId,
+                           aKeyId,
+                           dom::Optional<dom::MediaKeyStatus>(aStatus));
+}
+
+void
+GMPCDMCallbackProxy::ForgetKeyStatus(const nsCString& aSessionId,
+                                     const nsTArray<uint8_t>& aKeyId)
+{
+  MOZ_ASSERT(mProxy->IsOnOwnerThread());
+
+  KeyStatusChangedInternal(aSessionId,
+                           aKeyId,
+                           dom::Optional<dom::MediaKeyStatus>());
+}
+
+void
+GMPCDMCallbackProxy::KeyStatusChangedInternal(const nsCString& aSessionId,
+                                              const nsTArray<uint8_t>& aKeyId,
+                                              const dom::Optional<dom::MediaKeyStatus>& aStatus)
+{
   bool keyStatusesChange = false;
   {
     CDMCaps::AutoLock caps(mProxy->Capabilites());
     keyStatusesChange = caps.SetKeyStatus(aKeyId,
                                           NS_ConvertUTF8toUTF16(aSessionId),
                                           aStatus);
   }
   if (keyStatusesChange) {
     nsCOMPtr<nsIRunnable> task;
     task = NewRunnableMethod<nsString>(mProxy,
                                        &CDMProxy::OnKeyStatusesChange,
                                        NS_ConvertUTF8toUTF16(aSessionId));
     NS_DispatchToMainThread(task);
   }
 }
 
-DecryptStatus
-ToDecryptStatus(GMPErr aError)
-{
-  switch (aError) {
-    case GMPNoErr: return Ok;
-    case GMPNoKeyErr: return NoKeyErr;
-    case GMPAbortedErr: return AbortedErr;
-    default: return GenericErr;
-  }
-}
-
 void
 GMPCDMCallbackProxy::Decrypted(uint32_t aId,
-                               GMPErr aResult,
+                               DecryptStatus aResult,
                                const nsTArray<uint8_t>& aDecryptedData)
 {
   MOZ_ASSERT(mProxy->IsOnOwnerThread());
 
-  mProxy->OnDecrypted(aId, ToDecryptStatus(aResult), aDecryptedData);
+  mProxy->OnDecrypted(aId, aResult, aDecryptedData);
 }
 
 void
 GMPCDMCallbackProxy::Terminated()
 {
   MOZ_ASSERT(mProxy->IsOnOwnerThread());
   nsCOMPtr<nsIRunnable> task = NewRunnableMethod(mProxy, &CDMProxy::Terminated);
   NS_DispatchToMainThread(task);
--- a/dom/media/gmp/GMPCDMCallbackProxy.h
+++ b/dom/media/gmp/GMPCDMCallbackProxy.h
@@ -25,44 +25,50 @@ public:
 
   void ResolvePromise(uint32_t aPromiseId) override;
 
   void RejectPromise(uint32_t aPromiseId,
                      nsresult aException,
                      const nsCString& aSessionId) override;
 
   void SessionMessage(const nsCString& aSessionId,
-                      GMPSessionMessageType aMessageType,
+                      dom::MediaKeyMessageType aMessageType,
                       const nsTArray<uint8_t>& aMessage) override;
 
   void ExpirationChange(const nsCString& aSessionId,
-                        GMPTimestamp aExpiryTime) override;
+                        UnixTime aExpiryTime) override;
 
   void SessionClosed(const nsCString& aSessionId) override;
 
   void SessionError(const nsCString& aSessionId,
                     nsresult aException,
                     uint32_t aSystemCode,
                     const nsCString& aMessage) override;
 
   void KeyStatusChanged(const nsCString& aSessionId,
                         const nsTArray<uint8_t>& aKeyId,
-                        GMPMediaKeyStatus aStatus) override;
+                        dom::MediaKeyStatus aStatus) override;
+
+  void ForgetKeyStatus(const nsCString& aSessionId,
+                       const nsTArray<uint8_t>& aKeyId) override;
 
   void Decrypted(uint32_t aId,
-                 GMPErr aResult,
+                 DecryptStatus aResult,
                  const nsTArray<uint8_t>& aDecryptedData) override;
 
   void Terminated() override;
 
   ~GMPCDMCallbackProxy() {}
 
 private:
   friend class GMPCDMProxy;
   explicit GMPCDMCallbackProxy(CDMProxy* aProxy);
+  void KeyStatusChangedInternal(const nsCString& aSessionId,
+                                const nsTArray<uint8_t>& aKeyId,
+                                const dom::Optional<dom::MediaKeyStatus>& aStatus);
 
   // Warning: Weak ref.
   CDMProxy* mProxy;
 };
 
 } // namespace mozilla
 
 #endif // GMPCDMCallbackProxy_h_
--- a/dom/media/gmp/GMPDecryptorChild.cpp
+++ b/dom/media/gmp/GMPDecryptorChild.cpp
@@ -156,19 +156,26 @@ void
 GMPDecryptorChild::KeyStatusChanged(const char* aSessionId,
                                     uint32_t aSessionIdLength,
                                     const uint8_t* aKeyId,
                                     uint32_t aKeyIdLength,
                                     GMPMediaKeyStatus aStatus)
 {
   AutoTArray<uint8_t, 16> kid;
   kid.AppendElements(aKeyId, aKeyIdLength);
-  CALL_ON_GMP_THREAD(SendKeyStatusChanged,
-                     nsCString(aSessionId, aSessionIdLength), kid,
-                     aStatus);
+  if (aStatus == kGMPUnknown) {
+    CALL_ON_GMP_THREAD(SendForgetKeyStatus,
+                       nsCString(aSessionId, aSessionIdLength),
+                       kid);
+  } else {
+    CALL_ON_GMP_THREAD(SendKeyStatusChanged,
+                       nsCString(aSessionId, aSessionIdLength),
+                       kid,
+                       aStatus);
+  }
 }
 
 void
 GMPDecryptorChild::Decrypted(GMPBuffer* aBuffer, GMPErr aResult)
 {
   if (!ON_GMP_THREAD()) {
     // We should run this whole method on the GMP thread since the buffer needs
     // to be deleted after the SendDecrypted call.
--- a/dom/media/gmp/GMPDecryptorParent.cpp
+++ b/dom/media/gmp/GMPDecryptorParent.cpp
@@ -260,29 +260,41 @@ GMPDecryptorParent::RecvRejectPromise(co
   if (!mIsOpen) {
     NS_WARNING("Trying to use a dead GMP decrypter!");
     return false;
   }
   mCallback->RejectPromise(aPromiseId, GMPExToNsresult(aException), aMessage);
   return true;
 }
 
+
+static dom::MediaKeyMessageType
+ToMediaKeyMessageType(GMPSessionMessageType aMessageType) {
+  switch (aMessageType) {
+    case kGMPLicenseRequest: return dom::MediaKeyMessageType::License_request;
+    case kGMPLicenseRenewal: return dom::MediaKeyMessageType::License_renewal;
+    case kGMPLicenseRelease: return dom::MediaKeyMessageType::License_release;
+    case kGMPIndividualizationRequest: return dom::MediaKeyMessageType::Individualization_request;
+    default: return dom::MediaKeyMessageType::License_request;
+  };
+};
+
 bool
 GMPDecryptorParent::RecvSessionMessage(const nsCString& aSessionId,
                                        const GMPSessionMessageType& aMessageType,
                                        nsTArray<uint8_t>&& aMessage)
 {
   LOGD(("GMPDecryptorParent[%p]::RecvSessionMessage(sessionId='%s', type=%d, msg='%s')",
         this, aSessionId.get(), aMessageType, ToBase64(aMessage).get()));
 
   if (!mIsOpen) {
     NS_WARNING("Trying to use a dead GMP decrypter!");
     return false;
   }
-  mCallback->SessionMessage(aSessionId, aMessageType, aMessage);
+  mCallback->SessionMessage(aSessionId, ToMediaKeyMessageType(aMessageType), aMessage);
   return true;
 }
 
 bool
 GMPDecryptorParent::RecvExpirationChange(const nsCString& aSessionId,
                                          const double& aExpiryTime)
 {
   LOGD(("GMPDecryptorParent[%p]::RecvExpirationChange(sessionId='%s', expiry=%lf)",
@@ -326,43 +338,81 @@ GMPDecryptorParent::RecvSessionError(con
   }
   mCallback->SessionError(aSessionId,
                           GMPExToNsresult(aException),
                           aSystemCode,
                           aMessage);
   return true;
 }
 
+static dom::MediaKeyStatus
+ToMediaKeyStatus(GMPMediaKeyStatus aStatus) {
+  switch (aStatus) {
+    case kGMPUsable: return dom::MediaKeyStatus::Usable;
+    case kGMPExpired: return dom::MediaKeyStatus::Expired;
+    case kGMPOutputDownscaled: return dom::MediaKeyStatus::Output_downscaled;
+    case kGMPOutputRestricted: return dom::MediaKeyStatus::Output_restricted;
+    case kGMPInternalError: return dom::MediaKeyStatus::Internal_error;
+    case kGMPReleased: return dom::MediaKeyStatus::Released;
+    case kGMPStatusPending: return dom::MediaKeyStatus::Status_pending;
+    default: return dom::MediaKeyStatus::Internal_error;
+  }
+}
+
 bool
 GMPDecryptorParent::RecvKeyStatusChanged(const nsCString& aSessionId,
                                          InfallibleTArray<uint8_t>&& aKeyId,
                                          const GMPMediaKeyStatus& aStatus)
 {
   LOGD(("GMPDecryptorParent[%p]::RecvKeyStatusChanged(sessionId='%s', keyId=%s, status=%d)",
         this, aSessionId.get(), ToBase64(aKeyId).get(), aStatus));
 
   if (mIsOpen) {
-    mCallback->KeyStatusChanged(aSessionId, aKeyId, aStatus);
+    mCallback->KeyStatusChanged(aSessionId, aKeyId, ToMediaKeyStatus(aStatus));
   }
   return true;
 }
 
 bool
+GMPDecryptorParent::RecvForgetKeyStatus(const nsCString& aSessionId,
+                                        InfallibleTArray<uint8_t>&& aKeyId)
+{
+  LOGD(("GMPDecryptorParent[%p]::RecvForgetKeyStatus(sessionId='%s', keyId=%s)",
+        this, aSessionId.get(), ToBase64(aKeyId).get()));
+
+  if (mIsOpen) {
+    mCallback->ForgetKeyStatus(aSessionId, aKeyId);
+  }
+  return true;
+}
+
+DecryptStatus
+ToDecryptStatus(GMPErr aError)
+{
+  switch (aError) {
+    case GMPNoErr: return Ok;
+    case GMPNoKeyErr: return NoKeyErr;
+    case GMPAbortedErr: return AbortedErr;
+    default: return GenericErr;
+  }
+}
+
+bool
 GMPDecryptorParent::RecvDecrypted(const uint32_t& aId,
                                   const GMPErr& aErr,
                                   InfallibleTArray<uint8_t>&& aBuffer)
 {
   LOGV(("GMPDecryptorParent[%p]::RecvDecrypted(id=%d, err=%d)",
         this, aId, aErr));
 
   if (!mIsOpen) {
     NS_WARNING("Trying to use a dead GMP decrypter!");
     return false;
   }
-  mCallback->Decrypted(aId, aErr, aBuffer);
+  mCallback->Decrypted(aId, ToDecryptStatus(aErr), aBuffer);
   return true;
 }
 
 bool
 GMPDecryptorParent::RecvShutdown()
 {
   LOGD(("GMPDecryptorParent[%p]::RecvShutdown()", this));
 
--- a/dom/media/gmp/GMPDecryptorParent.h
+++ b/dom/media/gmp/GMPDecryptorParent.h
@@ -97,16 +97,19 @@ private:
                         const GMPDOMException& aException,
                         const uint32_t& aSystemCode,
                         const nsCString& aMessage) override;
 
   bool RecvKeyStatusChanged(const nsCString& aSessionId,
                             InfallibleTArray<uint8_t>&& aKeyId,
                             const GMPMediaKeyStatus& aStatus) override;
 
+  bool RecvForgetKeyStatus(const nsCString& aSessionId,
+                           InfallibleTArray<uint8_t>&& aKeyId) override;
+
   bool RecvDecrypted(const uint32_t& aId,
                      const GMPErr& aErr,
                      InfallibleTArray<uint8_t>&& aBuffer) override;
 
   bool RecvShutdown() override;
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
   bool Recv__delete__() override;
--- a/dom/media/gmp/PGMPDecryptor.ipdl
+++ b/dom/media/gmp/PGMPDecryptor.ipdl
@@ -77,15 +77,17 @@ parent:
   async SessionError(nsCString aSessionId,
                      GMPDOMException aDOMExceptionCode,
                      uint32_t aSystemCode,
                      nsCString aMessage);
 
   async KeyStatusChanged(nsCString aSessionId, uint8_t[] aKey,
                          GMPMediaKeyStatus aStatus);
 
+  async ForgetKeyStatus(nsCString aSessionId, uint8_t[] aKey);
+
   async Decrypted(uint32_t aId, GMPErr aResult, uint8_t[] aBuffer);
 
   async Shutdown();
 };
 
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gtest/TestGMPCrossOrigin.cpp
+++ b/dom/media/gtest/TestGMPCrossOrigin.cpp
@@ -17,16 +17,18 @@
 #include "MediaPrefs.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsIFile.h"
 #include "nsISimpleEnumerator.h"
 #include "mozilla/Atomics.h"
 #include "nsNSSComponent.h"
 #include "mozilla/DebugOnly.h"
 #include "GMPDeviceBinding.h"
+#include "mozilla/dom/MediaKeyStatusMapBinding.h" // For MediaKeyStatus
+#include "mozilla/dom/MediaKeyMessageEventBinding.h" // For MediaKeyMessageType
 
 #if defined(XP_WIN)
 #include "mozilla/WindowsVersion.h"
 #endif
 
 using namespace std;
 
 using namespace mozilla;
@@ -1339,17 +1341,17 @@ class GMPStorageTest : public GMPDecrypt
 
   void SetFinished() {
     mFinished = true;
     Shutdown();
     NS_DispatchToMainThread(NewRunnableMethod(this, &GMPStorageTest::Dummy));
   }
 
   void SessionMessage(const nsCString& aSessionId,
-                      GMPSessionMessageType aMessageType,
+                      mozilla::dom::MediaKeyMessageType aMessageType,
                       const nsTArray<uint8_t>& aMessage) override
   {
     MonitorAutoLock mon(mMonitor);
 
     nsCString msg((const char*)aMessage.Elements(), aMessage.Length());
     EXPECT_TRUE(mExpected.Length() > 0);
     bool matches = mExpected[0].mMessage.Equals(msg);
     EXPECT_STREQ(mExpected[0].mMessage.get(), msg.get());
@@ -1366,27 +1368,31 @@ class GMPStorageTest : public GMPDecrypt
                     const nsCString& aSessionId) override { }
   void ResolveLoadSessionPromise(uint32_t aPromiseId,
                                  bool aSuccess) override {}
   void ResolvePromise(uint32_t aPromiseId) override {}
   void RejectPromise(uint32_t aPromiseId,
                      nsresult aException,
                      const nsCString& aSessionId) override { }
   void ExpirationChange(const nsCString& aSessionId,
-                        GMPTimestamp aExpiryTime) override {}
+                        UnixTime aExpiryTime) override {}
   void SessionClosed(const nsCString& aSessionId) override {}
   void SessionError(const nsCString& aSessionId,
                     nsresult aException,
                     uint32_t aSystemCode,
                     const nsCString& aMessage) override {}
   void KeyStatusChanged(const nsCString& aSessionId,
                         const nsTArray<uint8_t>& aKeyId,
-                        GMPMediaKeyStatus aStatus) override { }
+                        mozilla::dom::MediaKeyStatus aStatus) override { }
+
+  void ForgetKeyStatus(const nsCString& aSessionId,
+                       const nsTArray<uint8_t>& aKeyId) override { }
+
   void Decrypted(uint32_t aId,
-                 GMPErr aResult,
+                 mozilla::DecryptStatus aResult,
                  const nsTArray<uint8_t>& aDecryptedData) override { }
   void Terminated() override {
     if (mDecryptor) {
       mDecryptor->Close();
       mDecryptor = nullptr;
     }
   }