Bug 1066425 - Make GMPDecryptorChild callbacks work off GMP thread - r=cpearce
authorEdwin Flores <eflores@mozilla.com>
Wed, 24 Sep 2014 10:04:48 +1200
changeset 222388 4db41aa61692a809def11f7e4236e84be2880c29
parent 222387 85c5138960fb2bbc29ccac5562b711754189e086
child 222389 031f438aaa235892c430fee69e74bc516a476def
push id7107
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 17:43:31 +0000
treeherdermozilla-aurora@b4b34e0acc75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1066425
milestone35.0a1
Bug 1066425 - Make GMPDecryptorChild callbacks work off GMP thread - r=cpearce
content/media/gmp/GMPChild.cpp
content/media/gmp/GMPDecryptorChild.cpp
content/media/gmp/GMPDecryptorChild.h
content/media/gmp/gmp-api/gmp-decryption.h
--- a/content/media/gmp/GMPChild.cpp
+++ b/content/media/gmp/GMPChild.cpp
@@ -390,23 +390,25 @@ GMPChild::DeallocPGMPVideoDecoderChild(P
 {
   delete aActor;
   return true;
 }
 
 PGMPDecryptorChild*
 GMPChild::AllocPGMPDecryptorChild()
 {
-  return new GMPDecryptorChild(this);
+  GMPDecryptorChild* actor = new GMPDecryptorChild(this);
+  actor->AddRef();
+  return actor;
 }
 
 bool
 GMPChild::DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor)
 {
-  delete aActor;
+  static_cast<GMPDecryptorChild*>(aActor)->Release();
   return true;
 }
 
 bool
 GMPChild::RecvPGMPAudioDecoderConstructor(PGMPAudioDecoderChild* aActor)
 {
   auto vdc = static_cast<GMPAudioDecoderChild*>(aActor);
 
--- a/content/media/gmp/GMPDecryptorChild.cpp
+++ b/content/media/gmp/GMPDecryptorChild.cpp
@@ -2,26 +2,38 @@
 /* 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/. */
 
 #include "GMPDecryptorChild.h"
 #include "GMPChild.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/unused.h"
+#include "runnable_utils.h"
 #include <ctime>
 
+#define ON_GMP_THREAD() (mPlugin->GMPMessageLoop() == MessageLoop::current())
+
+#define CALL_ON_GMP_THREAD(_func, ...) \
+  do { \
+    if (ON_GMP_THREAD()) { \
+      _func(__VA_ARGS__); \
+    } else { \
+      mPlugin->GMPMessageLoop()->PostTask( \
+        FROM_HERE, NewRunnableMethod(this, &GMPDecryptorChild::_func, __VA_ARGS__) \
+      ); \
+    } \
+  } while(false)
+
 namespace mozilla {
 namespace gmp {
 
 GMPDecryptorChild::GMPDecryptorChild(GMPChild* aPlugin)
   : mSession(nullptr)
-#ifdef DEBUG
   , mPlugin(aPlugin)
-#endif
 {
   MOZ_ASSERT(mPlugin);
 }
 
 GMPDecryptorChild::~GMPDecryptorChild()
 {
 }
 
@@ -32,143 +44,130 @@ GMPDecryptorChild::Init(GMPDecryptor* aS
   mSession = aSession;
 }
 
 void
 GMPDecryptorChild::ResolveNewSessionPromise(uint32_t aPromiseId,
                                             const char* aSessionId,
                                             uint32_t aSessionIdLength)
 {
-  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
-
-  nsAutoCString id(aSessionId, aSessionIdLength);
-  SendResolveNewSessionPromise(aPromiseId, id);
+  CALL_ON_GMP_THREAD(SendResolveNewSessionPromise,
+                     aPromiseId, nsAutoCString(aSessionId, aSessionIdLength));
 }
 
 void
 GMPDecryptorChild::ResolvePromise(uint32_t aPromiseId)
 {
-  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
-
-  SendResolvePromise(aPromiseId);
+  CALL_ON_GMP_THREAD(SendResolvePromise, aPromiseId);
 }
 
 void
 GMPDecryptorChild::RejectPromise(uint32_t aPromiseId,
                                  GMPDOMException aException,
                                  const char* aMessage,
                                  uint32_t aMessageLength)
 {
-  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
-
-  nsAutoCString msg(aMessage, aMessageLength);
-  SendRejectPromise(aPromiseId, aException, msg);
+  CALL_ON_GMP_THREAD(SendRejectPromise,
+                     aPromiseId, aException, nsAutoCString(aMessage, aMessageLength));
 }
 
 void
 GMPDecryptorChild::SessionMessage(const char* aSessionId,
                                   uint32_t aSessionIdLength,
                                   const uint8_t* aMessage,
                                   uint32_t aMessageLength,
                                   const char* aDestinationURL,
                                   uint32_t aDestinationURLLength)
 {
-  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
-
-  nsAutoCString id(aSessionId, aSessionIdLength);
   nsTArray<uint8_t> msg;
   msg.AppendElements(aMessage, aMessageLength);
-  nsAutoCString url(aDestinationURL, aDestinationURLLength);
-  SendSessionMessage(id, msg, url);
+  CALL_ON_GMP_THREAD(SendSessionMessage,
+                     nsAutoCString(aSessionId, aSessionIdLength), msg,
+                     nsAutoCString(aDestinationURL, aDestinationURLLength));
 }
 
 void
 GMPDecryptorChild::ExpirationChange(const char* aSessionId,
                                     uint32_t aSessionIdLength,
                                     GMPTimestamp aExpiryTime)
 {
-  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
-
-  nsAutoCString id(aSessionId, aSessionIdLength);
-  SendExpirationChange(id, aExpiryTime);
+  CALL_ON_GMP_THREAD(SendExpirationChange,
+                     nsAutoCString(aSessionId, aSessionIdLength), aExpiryTime);
 }
 
 void
 GMPDecryptorChild::SessionClosed(const char* aSessionId,
                                  uint32_t aSessionIdLength)
 {
-  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
-
-  nsAutoCString id(aSessionId, aSessionIdLength);
-  SendSessionClosed(id);
+  CALL_ON_GMP_THREAD(SendSessionClosed,
+                     nsAutoCString(aSessionId, aSessionIdLength));
 }
 
 void
 GMPDecryptorChild::SessionError(const char* aSessionId,
                                 uint32_t aSessionIdLength,
                                 GMPDOMException aException,
                                 uint32_t aSystemCode,
                                 const char* aMessage,
                                 uint32_t aMessageLength)
 {
-  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
-
-  nsAutoCString id(aSessionId, aSessionIdLength);
-  nsAutoCString msg(aMessage, aMessageLength);
-  SendSessionError(id, aException, aSystemCode, msg);
+  CALL_ON_GMP_THREAD(SendSessionError,
+                     nsAutoCString(aSessionId, aSessionIdLength),
+                     aException, aSystemCode,
+                     nsAutoCString(aMessage, aMessageLength));
 }
 
 void
 GMPDecryptorChild::KeyIdUsable(const char* aSessionId,
                                uint32_t aSessionIdLength,
                                const uint8_t* aKeyId,
                                uint32_t aKeyIdLength)
 {
-  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
-
-  nsAutoCString sid(aSessionId, aSessionIdLength);
   nsAutoTArray<uint8_t, 16> kid;
   kid.AppendElements(aKeyId, aKeyIdLength);
-  SendKeyIdUsable(sid, kid);
+  CALL_ON_GMP_THREAD(SendKeyIdUsable,
+                     nsAutoCString(aSessionId, aSessionIdLength), kid);
 }
 
 void
 GMPDecryptorChild::KeyIdNotUsable(const char* aSessionId,
                                   uint32_t aSessionIdLength,
                                   const uint8_t* aKeyId,
                                   uint32_t aKeyIdLength)
 {
-  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
-
-  nsAutoCString sid(aSessionId, aSessionIdLength);
   nsAutoTArray<uint8_t, 16> kid;
   kid.AppendElements(aKeyId, aKeyIdLength);
-  SendKeyIdNotUsable(sid, kid);
+  CALL_ON_GMP_THREAD(SendKeyIdNotUsable,
+                     nsAutoCString(aSessionId, aSessionIdLength), kid);
 }
 
 void
 GMPDecryptorChild::Decrypted(GMPBuffer* aBuffer, GMPErr aResult)
 {
-  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
+  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.
+    CALL_ON_GMP_THREAD(Decrypted, aBuffer, aResult);
+    return;
+  }
 
   if (!aBuffer) {
     NS_WARNING("GMPDecryptorCallback passed bull GMPBuffer");
     return;
   }
+
   auto buffer = static_cast<GMPBufferImpl*>(aBuffer);
   SendDecrypted(buffer->mId, aResult, buffer->mData);
   delete buffer;
 }
 
 void
 GMPDecryptorChild::SetCapabilities(uint64_t aCaps)
 {
-  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
-
-  SendSetCaps(aCaps);
+  CALL_ON_GMP_THREAD(SendSetCaps, aCaps);
 }
 
 void
 GMPDecryptorChild::GetNodeId(const char** aOutNodeId,
                              uint32_t* aOutNodeIdLength)
 {
   static const char* id = "placeholder_node_id";
   *aOutNodeId = id;
--- a/content/media/gmp/GMPDecryptorChild.h
+++ b/content/media/gmp/GMPDecryptorChild.h
@@ -16,18 +16,19 @@ namespace gmp {
 
 class GMPChild;
 
 class GMPDecryptorChild : public GMPDecryptorCallback
                         , public GMPDecryptorHost
                         , public PGMPDecryptorChild
 {
 public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPDecryptorChild);
+
   explicit GMPDecryptorChild(GMPChild* aPlugin);
-  ~GMPDecryptorChild();
 
   void Init(GMPDecryptor* aSession);
 
   // GMPDecryptorCallback
   virtual void ResolveNewSessionPromise(uint32_t aPromiseId,
                                         const char* aSessionId,
                                         uint32_t aSessionIdLength) MOZ_OVERRIDE;
   virtual void ResolvePromise(uint32_t aPromiseId) MOZ_OVERRIDE;
@@ -77,16 +78,17 @@ public:
                          uint32_t* aOutNodeIdLength) MOZ_OVERRIDE;
 
   virtual void GetSandboxVoucher(const uint8_t** aVoucher,
                                  uint8_t* aVoucherLength) MOZ_OVERRIDE;
 
   virtual void GetPluginVoucher(const uint8_t** aVoucher,
                                 uint8_t* aVoucherLength) MOZ_OVERRIDE;
 private:
+  ~GMPDecryptorChild();
 
   // GMPDecryptorChild
   virtual bool RecvInit() MOZ_OVERRIDE;
 
   virtual bool RecvCreateSession(const uint32_t& aPromiseId,
                                  const nsCString& aInitDataType,
                                  const nsTArray<uint8_t>& aInitData,
                                  const GMPSessionType& aSessionType) MOZ_OVERRIDE;
@@ -112,18 +114,15 @@ private:
   virtual bool RecvSetServerCertificate(const uint32_t& aPromiseId,
                                         const nsTArray<uint8_t>& aServerCert) MOZ_OVERRIDE;
 
   virtual bool RecvDecryptingComplete() MOZ_OVERRIDE;
 
   // GMP's GMPDecryptor implementation.
   // Only call into this on the (GMP process) main thread.
   GMPDecryptor* mSession;
-
-#ifdef DEBUG
   GMPChild* mPlugin;
-#endif
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPDecryptorChild_h_
--- a/content/media/gmp/gmp-api/gmp-decryption.h
+++ b/content/media/gmp/gmp-api/gmp-decryption.h
@@ -86,16 +86,17 @@ typedef int64_t GMPTimestamp;
 #define GMP_EME_CAP_DECRYPT_AUDIO (uint64_t(1) << 0)
 #define GMP_EME_CAP_DECRYPT_VIDEO (uint64_t(1) << 1)
 
 // Capability; CDM can decrypt and then decode encrypted buffers,
 // and return decompressed samples to Gecko for playback.
 #define GMP_EME_CAP_DECRYPT_AND_DECODE_AUDIO (uint64_t(1) << 2)
 #define GMP_EME_CAP_DECRYPT_AND_DECODE_VIDEO (uint64_t(1) << 3)
 
+// Callbacks to be called from the CDM. Threadsafe.
 class GMPDecryptorCallback {
 public:
   // Resolves a promise for a session created or loaded.
   // Passes the session id to be exposed to JavaScript.
   // Must be called before SessionMessage().
   // aSessionId must be null terminated.
   virtual void ResolveNewSessionPromise(uint32_t aPromiseId,
                                         const char* aSessionId,