Backed out 3 changesets (bug 1318965) for frequent media test failures a=backout
authorWes Kocher <wkocher@mozilla.com>
Fri, 13 Jan 2017 13:23:31 -0800
changeset 376647 ee205312f370c1b6fbbaa20f6bb9eac4aa95d06f
parent 376646 87a39313365a178ce080e5613ee7b29b107e684e
child 376648 ac3275723df59db0f09198fdb61b51e7002c391a
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1318965
milestone53.0a1
backs out3f756d8ee4cf3847773ca1ffc6999948f670455b
4bdf65d60c9ec4f086c76554ff3fe5ecc44bd889
c1e2b6c14a7f267c5458e9edab5e86f67a6d073f
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 3 changesets (bug 1318965) for frequent media test failures a=backout Backed out changeset 3f756d8ee4cf (bug 1318965) Backed out changeset 4bdf65d60c9e (bug 1318965) Backed out changeset c1e2b6c14a7f (bug 1318965) MozReview-Commit-ID: 6CPk5oS5AOw
dom/media/gmp/moz.build
dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
media/gmp-clearkey/0.1/AnnexB.cpp
media/gmp-clearkey/0.1/AnnexB.h
media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.cpp
media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.h
media/gmp-clearkey/0.1/ClearKeyCDM.cpp
media/gmp-clearkey/0.1/ClearKeyCDM.h
media/gmp-clearkey/0.1/ClearKeyDecryptionManager.cpp
media/gmp-clearkey/0.1/ClearKeyDecryptionManager.h
media/gmp-clearkey/0.1/ClearKeyPersistence.cpp
media/gmp-clearkey/0.1/ClearKeyPersistence.h
media/gmp-clearkey/0.1/ClearKeySession.cpp
media/gmp-clearkey/0.1/ClearKeySession.h
media/gmp-clearkey/0.1/ClearKeySessionManager.cpp
media/gmp-clearkey/0.1/ClearKeySessionManager.h
media/gmp-clearkey/0.1/ClearKeyStorage.cpp
media/gmp-clearkey/0.1/ClearKeyStorage.h
media/gmp-clearkey/0.1/ClearKeyUtils.cpp
media/gmp-clearkey/0.1/ClearKeyUtils.h
media/gmp-clearkey/0.1/RefCounted.h
media/gmp-clearkey/0.1/VideoDecoder.cpp
media/gmp-clearkey/0.1/VideoDecoder.h
media/gmp-clearkey/0.1/WMFH264Decoder.cpp
media/gmp-clearkey/0.1/WMFH264Decoder.h
media/gmp-clearkey/0.1/WMFUtils.h
media/gmp-clearkey/0.1/gmp-clearkey.cpp
media/gmp-clearkey/0.1/gmp-task-utils-generated.h
media/gmp-clearkey/0.1/gmp-task-utils.h
media/gmp-clearkey/0.1/moz.build
--- a/dom/media/gmp/moz.build
+++ b/dom/media/gmp/moz.build
@@ -67,17 +67,16 @@ EXPORTS += [
     'GMPVideoDecoderProxy.h',
     'GMPVideoEncodedFrameImpl.h',
     'GMPVideoEncoderChild.h',
     'GMPVideoEncoderParent.h',
     'GMPVideoEncoderProxy.h',
     'GMPVideoHost.h',
     'GMPVideoi420FrameImpl.h',
     'GMPVideoPlaneImpl.h',
-    'widevine-adapter/content_decryption_module.h',
 ]
 
 # We link GMPLoader into xul on Android and Linux as its code does not
 # need to be covered by a DRM vendor's voucher.
 if CONFIG['OS_ARCH'] == 'Linux':
     SOURCES += [
       'GMPLoader.cpp',
     ]
@@ -115,17 +114,17 @@ UNIFIED_SOURCES += [
     'GMPUtils.cpp',
     'GMPVideoDecoderChild.cpp',
     'GMPVideoDecoderParent.cpp',
     'GMPVideoEncodedFrameImpl.cpp',
     'GMPVideoEncoderChild.cpp',
     'GMPVideoEncoderParent.cpp',
     'GMPVideoHost.cpp',
     'GMPVideoi420FrameImpl.cpp',
-    'GMPVideoPlaneImpl.cpp'
+    'GMPVideoPlaneImpl.cpp',
 ]
 
 DIRS += [
     'rlz',
     'widevine-adapter',
 ]
 
 IPDL_SOURCES += [
--- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
@@ -308,27 +308,16 @@ void
 WidevineDecryptor::OnResolveNewSessionPromise(uint32_t aPromiseId,
                                               const char* aSessionId,
                                               uint32_t aSessionIdSize)
 {
   if (!mCallback) {
     Log("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d) FAIL; !mCallback", aPromiseId);
     return;
   }
-
-  // This is laid out in the API. If we fail to load a session we should
-  // call OnResolveNewSessionPromise with nullptr as the sessionId.
-  // We can safely assume this means that we have failed to load a session
-  // as the other methods specify calling 'OnRejectPromise' when they fail.
-  if (!aSessionId) {
-    Log("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d) Failed to load session", aPromiseId);
-    mCallback->ResolveLoadSessionPromise(aPromiseId, false);
-    return;
-  }
-
   Log("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d)", aPromiseId);
   auto iter = mPromiseIdToNewSessionTokens.find(aPromiseId);
   if (iter == mPromiseIdToNewSessionTokens.end()) {
     Log("FAIL: Decryptor::OnResolveNewSessionPromise(aPromiseId=%d) unknown aPromiseId", aPromiseId);
     return;
   }
   mCallback->SetSessionId(iter->second, aSessionId, aSessionIdSize);
   mCallback->ResolvePromise(aPromiseId);
new file mode 100644
--- /dev/null
+++ b/media/gmp-clearkey/0.1/AnnexB.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2015, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AnnexB.h"
+#include "BigEndian.h"
+
+#include <cstring>
+
+using mozilla::BigEndian;
+
+static const uint8_t kAnnexBDelimiter[] = { 0, 0, 0, 1 };
+
+/* static */ void
+AnnexB::ConvertFrameInPlace(std::vector<uint8_t>& aBuffer)
+{
+  for (size_t i = 0; i < aBuffer.size() - 4 - sizeof(kAnnexBDelimiter) + 1; ) {
+    uint32_t nalLen = BigEndian::readUint32(&aBuffer[i]);
+    memcpy(&aBuffer[i], kAnnexBDelimiter, sizeof(kAnnexBDelimiter));
+    i += nalLen + 4;
+  }
+}
+
+static void
+ConvertParamSetToAnnexB(std::vector<uint8_t>::const_iterator& aIter,
+                        size_t aCount,
+                        std::vector<uint8_t>& aOutAnnexB)
+{
+  for (size_t i = 0; i < aCount; i++) {
+    aOutAnnexB.insert(aOutAnnexB.end(), kAnnexBDelimiter,
+                      kAnnexBDelimiter + sizeof(kAnnexBDelimiter));
+
+    uint16_t len = BigEndian::readUint16(&*aIter); aIter += 2;
+    aOutAnnexB.insert(aOutAnnexB.end(), aIter, aIter + len); aIter += len;
+  }
+}
+
+/* static */ void
+AnnexB::ConvertConfig(const std::vector<uint8_t>& aBuffer,
+                      std::vector<uint8_t>& aOutAnnexB)
+{
+  // Skip past irrelevant headers
+  auto it = aBuffer.begin() + 5;
+
+  if (it >= aBuffer.end()) {
+    return;
+  }
+
+  size_t count = *(it++) & 31;
+
+  // Check that we have enough bytes for the Annex B conversion
+  // and the next size field. Bail if not.
+  if (it + count * 2 >= aBuffer.end()) {
+    return;
+  }
+
+  ConvertParamSetToAnnexB(it, count, aOutAnnexB);
+
+  // Check that we have enough bytes for the Annex B conversion.
+  count = *(it++);
+  if (it + count * 2 > aBuffer.end()) {
+    aOutAnnexB.clear();
+    return;
+  }
+
+  ConvertParamSetToAnnexB(it, count, aOutAnnexB);
+}
new file mode 100644
--- /dev/null
+++ b/media/gmp-clearkey/0.1/AnnexB.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AnnexB_h__
+#define __AnnexB_h__
+
+#include <cstdint>
+#include <vector>
+
+class AnnexB
+{
+public:
+  static void ConvertFrameInPlace(std::vector<uint8_t>& aBuffer);
+
+  static void ConvertConfig(const std::vector<uint8_t>& aBuffer,
+                            std::vector<uint8_t>& aOutAnnexB);
+};
+
+#endif // __AnnexB_h__
new file mode 100644
--- /dev/null
+++ b/media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2015, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ClearKeyAsyncShutdown.h"
+#include "gmp-task-utils.h"
+
+ClearKeyAsyncShutdown::ClearKeyAsyncShutdown(GMPAsyncShutdownHost *aHostAPI)
+  : mHost(aHostAPI)
+{
+  CK_LOGD("ClearKeyAsyncShutdown::ClearKeyAsyncShutdown");
+  AddRef();
+}
+
+ClearKeyAsyncShutdown::~ClearKeyAsyncShutdown()
+{
+  CK_LOGD("ClearKeyAsyncShutdown::~ClearKeyAsyncShutdown");
+}
+
+void ShutdownTask(ClearKeyAsyncShutdown* aSelf, GMPAsyncShutdownHost* aHost)
+{
+  // Dumb implementation that just immediately reports completion.
+  // Real GMPs should ensure they are properly shutdown.
+  CK_LOGD("ClearKeyAsyncShutdown::BeginShutdown calling ShutdownComplete");
+  aHost->ShutdownComplete();
+  aSelf->Release();
+}
+
+void ClearKeyAsyncShutdown::BeginShutdown()
+{
+  CK_LOGD("ClearKeyAsyncShutdown::BeginShutdown dispatching asynchronous shutdown task");
+  GetPlatform()->runonmainthread(WrapTaskNM(ShutdownTask, this, mHost));
+}
new file mode 100644
--- /dev/null
+++ b/media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ClearKeyAsyncShutdown_h__
+#define __ClearKeyAsyncShutdown_h__
+
+#include "gmp-api/gmp-async-shutdown.h"
+#include "RefCounted.h"
+
+class ClearKeyAsyncShutdown : public GMPAsyncShutdown
+                            , public RefCounted
+{
+public:
+  explicit ClearKeyAsyncShutdown(GMPAsyncShutdownHost *aHostAPI);
+
+  void BeginShutdown() override;
+
+private:
+  virtual ~ClearKeyAsyncShutdown();
+
+  GMPAsyncShutdownHost* mHost;
+};
+
+#endif // __ClearKeyAsyncShutdown_h__
deleted file mode 100644
--- a/media/gmp-clearkey/0.1/ClearKeyCDM.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-#include "ClearKeyCDM.h"
-
-#include "ClearKeyUtils.h"
-
-using namespace cdm;
-
-ClearKeyCDM::ClearKeyCDM(Host_8* aHost)
-{
-  mHost = aHost;
-  mSessionManager = new ClearKeySessionManager(mHost);
-}
-
-void
-ClearKeyCDM::Initialize(bool aAllowDistinctiveIdentifier,
-                        bool aAllowPersistentState)
-{
-  mSessionManager->Init(aAllowDistinctiveIdentifier,
-                        aAllowPersistentState);
-
-#ifdef ENABLE_WMF
-  mVideoDecoder = new VideoDecoder(mHost);
-#endif
-}
-
-void
-ClearKeyCDM::SetServerCertificate(uint32_t aPromiseId,
-                                  const uint8_t* aServerCertificateData,
-                                  uint32_t aServerCertificateDataSize)
-{
-  mSessionManager->SetServerCertificate(aPromiseId,
-                                        aServerCertificateData,
-                                        aServerCertificateDataSize);
-}
-
-void
-ClearKeyCDM::CreateSessionAndGenerateRequest(uint32_t aPromiseId,
-                                             SessionType aSessionType,
-                                             InitDataType aInitDataType,
-                                             const uint8_t* aInitData,
-                                             uint32_t aInitDataSize)
-{
-  mSessionManager->CreateSession(aPromiseId,
-                                 aInitDataType,
-                                 aInitData,
-                                 aInitDataSize,
-                                 aSessionType);
-}
-
-void
-ClearKeyCDM::LoadSession(uint32_t aPromiseId,
-                         SessionType aSessionType,
-                         const char* aSessionId,
-                         uint32_t aSessionIdSize)
-{
-  mSessionManager->LoadSession(aPromiseId,
-                               aSessionId,
-                               aSessionIdSize);
-}
-
-void
-ClearKeyCDM::UpdateSession(uint32_t aPromiseId,
-                           const char* aSessionId,
-                           uint32_t aSessionIdSize,
-                           const uint8_t* aResponse,
-                           uint32_t aResponseSize)
-{
-  mSessionManager->UpdateSession(aPromiseId,
-                                 aSessionId,
-                                 aSessionIdSize,
-                                 aResponse,
-                                 aResponseSize);
-}
-
-void
-ClearKeyCDM::CloseSession(uint32_t aPromiseId,
-                          const char* aSessionId,
-                          uint32_t aSessionIdSize)
-{
-  mSessionManager->CloseSession(aPromiseId,
-                                aSessionId,
-                                aSessionIdSize);
-}
-
-void
-ClearKeyCDM::RemoveSession(uint32_t aPromiseId,
-                           const char* aSessionId,
-                           uint32_t aSessionIdSize)
-{
-  mSessionManager->RemoveSession(aPromiseId,
-                                 aSessionId,
-                                 aSessionIdSize);
-}
-
-void
-ClearKeyCDM::TimerExpired(void* aContext)
-{
-  // Clearkey is not interested in timers, so this method has not been
-  // implemented.
-  assert(false);
-}
-
-Status
-ClearKeyCDM::Decrypt(const InputBuffer& aEncryptedBuffer,
-                     DecryptedBlock* aDecryptedBuffer)
-{
-  return mSessionManager->Decrypt(aEncryptedBuffer, aDecryptedBuffer);
-}
-
-Status
-ClearKeyCDM::InitializeAudioDecoder(
-  const AudioDecoderConfig& aAudioDecoderConfig)
-{
-  // Audio decoding is not supported by Clearkey because Widevine doesn't
-  // support it and Clearkey's raison d'etre is to provide test coverage
-  // for paths that Widevine will exercise in the wild.
-  return Status::kDecodeError;
-}
-
-Status
-ClearKeyCDM::InitializeVideoDecoder(
-  const VideoDecoderConfig& aVideoDecoderConfig)
-{
-#ifdef ENABLE_WMF
-  return mVideoDecoder->InitDecode(aVideoDecoderConfig);
-#else
-  return Status::kDecodeError;
-#endif
-}
-
-void
-ClearKeyCDM::DeinitializeDecoder(StreamType aDecoderType)
-{
-#ifdef ENABLE_WMF
-  if (aDecoderType == StreamType::kStreamTypeVideo) {
-    mVideoDecoder->Reset();
-  }
-#endif
-}
-
-void
-ClearKeyCDM::ResetDecoder(StreamType aDecoderType)
-{
-#ifdef ENABLE_WMF
-  if (aDecoderType == StreamType::kStreamTypeVideo) {
-    mVideoDecoder->Reset();
-  }
-#endif
-}
-
-Status
-ClearKeyCDM::DecryptAndDecodeFrame(const InputBuffer& aEncryptedBuffer,
-                                   VideoFrame* aVideoFrame)
-{
-#ifdef ENABLE_WMF
-  return mVideoDecoder->Decode(aEncryptedBuffer, aVideoFrame);
-#else
-  return Status::kDecodeError;
-#endif
-}
-
-Status
-ClearKeyCDM::DecryptAndDecodeSamples(const InputBuffer& aEncryptedBuffer,
-                                     AudioFrames* aAudioFrame)
-{
-  // Audio decoding is not supported by Clearkey because Widevine doesn't
-  // support it and Clearkey's raison d'etre is to provide test coverage
-  // for paths that Widevine will exercise in the wild.
-  return Status::kDecodeError;
-}
-
-void
-ClearKeyCDM::OnPlatformChallengeResponse(
-  const PlatformChallengeResponse& aResponse)
-{
-  // This function should never be called and is not supported.
-  assert(false);
-}
-
-void
-ClearKeyCDM::OnQueryOutputProtectionStatus(QueryResult aResult,
-                                           uint32_t aLinkMask,
-                                           uint32_t aOutputProtectionMask)
-{
-  // This function should never be called and is not supported.
-  assert(false);
-}
-
-void
-ClearKeyCDM::Destroy()
-{
-  mSessionManager->DecryptingComplete();
-#ifdef ENABLE_WMF
-  mVideoDecoder->DecodingComplete();
-#endif
-}
\ No newline at end of file
deleted file mode 100644
--- a/media/gmp-clearkey/0.1/ClearKeyCDM.h
+++ /dev/null
@@ -1,98 +0,0 @@
-#ifndef ClearKeyCDM_h_
-#define ClearKeyCDM_h_
-
-#include "ClearKeySessionManager.h"
-
-// This include is required in order for content_decryption_module to work
-// on Unix systems.
-#include "stddef.h"
-#include "content_decryption_module.h"
-
-#ifdef ENABLE_WMF
-#include "WMFUtils.h"
-#include "VideoDecoder.h"
-#endif
-
-class ClearKeyCDM : public cdm::ContentDecryptionModule_8
-{
-private:
-  RefPtr<ClearKeySessionManager> mSessionManager;
-#ifdef ENABLE_WMF
-  RefPtr<VideoDecoder> mVideoDecoder;
-#endif
-
-protected:
-  cdm::Host_8* mHost;
-
-public:
-  explicit ClearKeyCDM(cdm::Host_8* mHost);
-
-  void Initialize(bool aAllowDistinctiveIdentifier,
-                  bool aAllowPersistentState) override;
-
-  void SetServerCertificate(uint32_t aPromiseId,
-                            const uint8_t* aServerCertificateData,
-                            uint32_t aServerCertificateDataSize)
-                            override;
-
-  void CreateSessionAndGenerateRequest(uint32_t aPromiseId,
-                                       cdm::SessionType aSessionType,
-                                       cdm::InitDataType aInitDataType,
-                                       const uint8_t* aInitData,
-                                       uint32_t aInitDataSize)
-                                       override;
-
-  void LoadSession(uint32_t aPromiseId,
-                   cdm::SessionType aSessionType,
-                   const char* aSessionId,
-                   uint32_t aSessionIdSize) override;
-
-  void UpdateSession(uint32_t aPromiseId,
-                     const char* aSessionId,
-                     uint32_t aSessionIdSize,
-                     const uint8_t* aResponse,
-                     uint32_t aResponseSize) override;
-
-  void CloseSession(uint32_t aPromiseId,
-                    const char* aSessionId,
-                    uint32_t aSessionIdSize) override;
-
-  void RemoveSession(uint32_t aPromiseId,
-                     const char* aSessionId,
-                     uint32_t aSessionIdSize) override;
-
-  void TimerExpired(void* aContext) override;
-
-  cdm::Status Decrypt(const cdm::InputBuffer& aEncryptedBuffer,
-                      cdm::DecryptedBlock* aDecryptedBuffer) override;
-
-  cdm::Status InitializeAudioDecoder(
-    const cdm::AudioDecoderConfig& aAudioDecoderConfig) override;
-
-  cdm::Status InitializeVideoDecoder(
-    const cdm::VideoDecoderConfig& aVideoDecoderConfig) override;
-
-  void DeinitializeDecoder(cdm::StreamType aDecoderType) override;
-
-  void ResetDecoder(cdm::StreamType aDecoderType) override;
-
-  cdm::Status DecryptAndDecodeFrame(
-    const cdm::InputBuffer& aEncryptedBuffer,
-    cdm::VideoFrame* aVideoFrame) override;
-
-  cdm::Status DecryptAndDecodeSamples(
-    const cdm::InputBuffer& aEncryptedBuffer,
-    cdm::AudioFrames* aAudioFrame) override;
-
-  void OnPlatformChallengeResponse(
-    const cdm::PlatformChallengeResponse& aResponse) override;
-
-  void
-    OnQueryOutputProtectionStatus(cdm::QueryResult aResult,
-                                  uint32_t aLinkMask,
-                                  uint32_t aOutputProtectionMask) override;
-
-  void Destroy() override;
-};
-
-#endif
\ No newline at end of file
--- a/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.cpp
@@ -9,48 +9,45 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-#include "ClearKeyDecryptionManager.h"
-
-#include "psshparser/PsshParser.h"
-
-#include <assert.h>
 #include <string.h>
 #include <vector>
 
-using namespace cdm;
+#include "ClearKeyDecryptionManager.h"
+#include "psshparser/PsshParser.h"
+#include "gmp-api/gmp-decryption.h"
+#include <assert.h>
 
 class ClearKeyDecryptor : public RefCounted
 {
 public:
   ClearKeyDecryptor();
 
   void InitKey(const Key& aKey);
   bool HasKey() const { return !!mKey.size(); }
 
-  Status Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
+  GMPErr Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
                  const CryptoMetaData& aMetadata);
 
   const Key& DecryptionKey() const { return mKey; }
 
 private:
   ~ClearKeyDecryptor();
 
   Key mKey;
 };
 
 
-/* static */ ClearKeyDecryptionManager*
-ClearKeyDecryptionManager::sInstance = nullptr;
+/* static */ ClearKeyDecryptionManager* ClearKeyDecryptionManager::sInstance = nullptr;
 
 /* static */ ClearKeyDecryptionManager*
 ClearKeyDecryptionManager::Get()
 {
   if (!sInstance) {
     sInstance = new ClearKeyDecryptionManager();
   }
   return sInstance;
@@ -71,27 +68,24 @@ ClearKeyDecryptionManager::~ClearKeyDecr
     it->second->Release();
   }
   mDecryptors.clear();
 }
 
 bool
 ClearKeyDecryptionManager::HasSeenKeyId(const KeyId& aKeyId) const
 {
-  CK_LOGD("ClearKeyDecryptionManager::SeenKeyId %s",
-          mDecryptors.find(aKeyId) != mDecryptors.end() ? "t" : "f");
+  CK_LOGD("ClearKeyDecryptionManager::SeenKeyId %s", mDecryptors.find(aKeyId) != mDecryptors.end() ? "t" : "f");
   return mDecryptors.find(aKeyId) != mDecryptors.end();
 }
 
 bool
 ClearKeyDecryptionManager::IsExpectingKeyForKeyId(const KeyId& aKeyId) const
 {
-  CK_LOGARRAY("ClearKeyDecryptionManager::IsExpectingKeyForId ",
-              aKeyId.data(),
-              aKeyId.size());
+  CK_LOGD("ClearKeyDecryptionManager::IsExpectingKeyForId %08x...", *(uint32_t*)&aKeyId[0]);
   const auto& decryptor = mDecryptors.find(aKeyId);
   return decryptor != mDecryptors.end() && !decryptor->second->HasKey();
 }
 
 bool
 ClearKeyDecryptionManager::HasKeyForKeyId(const KeyId& aKeyId) const
 {
   CK_LOGD("ClearKeyDecryptionManager::HasKeyForKeyId");
@@ -104,33 +98,26 @@ ClearKeyDecryptionManager::GetDecryption
 {
   assert(HasKeyForKeyId(aKeyId));
   return mDecryptors[aKeyId]->DecryptionKey();
 }
 
 void
 ClearKeyDecryptionManager::InitKey(KeyId aKeyId, Key aKey)
 {
-  CK_LOGD("ClearKeyDecryptionManager::InitKey ",
-          aKeyId.data(),
-          aKeyId.size());
+  CK_LOGD("ClearKeyDecryptionManager::InitKey %08x...", *(uint32_t*)&aKeyId[0]);
   if (IsExpectingKeyForKeyId(aKeyId)) {
-    CK_LOGARRAY("Initialized Key ", aKeyId.data(), aKeyId.size());
     mDecryptors[aKeyId]->InitKey(aKey);
-  } else {
-    CK_LOGARRAY("Failed to initialize key ", aKeyId.data(), aKeyId.size());
   }
 }
 
 void
 ClearKeyDecryptionManager::ExpectKeyId(KeyId aKeyId)
 {
-  CK_LOGD("ClearKeyDecryptionManager::ExpectKeyId ",
-          aKeyId.data(),
-          aKeyId.size());
+  CK_LOGD("ClearKeyDecryptionManager::ExpectKeyId %08x...", *(uint32_t*)&aKeyId[0]);
   if (!HasSeenKeyId(aKeyId)) {
     mDecryptors[aKeyId] = new ClearKeyDecryptor();
   }
   mDecryptors[aKeyId]->AddRef();
 }
 
 void
 ClearKeyDecryptionManager::ReleaseKeyId(KeyId aKeyId)
@@ -139,66 +126,56 @@ ClearKeyDecryptionManager::ReleaseKeyId(
   assert(HasSeenKeyId(aKeyId));
 
   ClearKeyDecryptor* decryptor = mDecryptors[aKeyId];
   if (!decryptor->Release()) {
     mDecryptors.erase(aKeyId);
   }
 }
 
-Status
+GMPErr
 ClearKeyDecryptionManager::Decrypt(std::vector<uint8_t>& aBuffer,
                                    const CryptoMetaData& aMetadata)
 {
   return Decrypt(&aBuffer[0], aBuffer.size(), aMetadata);
 }
 
-Status
+GMPErr
 ClearKeyDecryptionManager::Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
                                    const CryptoMetaData& aMetadata)
 {
   CK_LOGD("ClearKeyDecryptionManager::Decrypt");
   if (!HasKeyForKeyId(aMetadata.mKeyId)) {
-    CK_LOGARRAY("Unable to find decryptor for keyId: ",
-                aMetadata.mKeyId.data(),
-                aMetadata.mKeyId.size());
-    return Status::kNoKey;
+    return GMPNoKeyErr;
   }
 
-  CK_LOGARRAY("Found decryptor for keyId: ",
-              aMetadata.mKeyId.data(),
-              aMetadata.mKeyId.size());
-  return mDecryptors[aMetadata.mKeyId]->Decrypt(aBuffer,
-                                                aBufferSize,
-                                                aMetadata);
+  return mDecryptors[aMetadata.mKeyId]->Decrypt(aBuffer, aBufferSize, aMetadata);
 }
 
 ClearKeyDecryptor::ClearKeyDecryptor()
 {
   CK_LOGD("ClearKeyDecryptor ctor");
 }
 
 ClearKeyDecryptor::~ClearKeyDecryptor()
 {
   if (HasKey()) {
-    CK_LOGARRAY("ClearKeyDecryptor dtor; key = ",
-                mKey.data(),
-                mKey.size());
+    CK_LOGD("ClearKeyDecryptor dtor; key = %08x...", *(uint32_t*)&mKey[0]);
   } else {
     CK_LOGD("ClearKeyDecryptor dtor");
   }
 }
 
 void
 ClearKeyDecryptor::InitKey(const Key& aKey)
 {
   mKey = aKey;
 }
 
-Status
+GMPErr
 ClearKeyDecryptor::Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
                            const CryptoMetaData& aMetadata)
 {
   CK_LOGD("ClearKeyDecryptor::Decrypt");
   // If the sample is split up into multiple encrypted subsamples, we need to
   // stitch them into one continuous buffer for decryption.
   std::vector<uint8_t> tmp(aBufferSize);
 
@@ -207,17 +184,17 @@ ClearKeyDecryptor::Decrypt(uint8_t* aBuf
     // continuous encrypted buffer.
     uint8_t* data = aBuffer;
     uint8_t* iter = &tmp[0];
     for (size_t i = 0; i < aMetadata.NumSubsamples(); i++) {
       data += aMetadata.mClearBytes[i];
       uint32_t cipherBytes = aMetadata.mCipherBytes[i];
       if (data + cipherBytes > aBuffer + aBufferSize) {
         // Trying to read past the end of the buffer!
-        return Status::kDecryptError;
+        return GMPCryptoErr;
       }
 
       memcpy(iter, data, cipherBytes);
 
       data += cipherBytes;
       iter += cipherBytes;
     }
 
@@ -245,10 +222,10 @@ ClearKeyDecryptor::Decrypt(uint8_t* aBuf
 
       data += cipherBytes;
       iter += cipherBytes;
     }
   } else {
     memcpy(aBuffer, &tmp[0], aBufferSize);
   }
 
-  return Status::kSuccess;
+  return GMPNoErr;
 }
--- a/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.h
+++ b/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.h
@@ -12,70 +12,59 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef __ClearKeyDecryptionManager_h__
 #define __ClearKeyDecryptionManager_h__
 
+#include <map>
+
 #include "ClearKeyUtils.h"
-// This include is required in order for content_decryption_module to work
-// on Unix systems.
-#include "stddef.h"
-#include "content_decryption_module.h"
 #include "RefCounted.h"
 
-#include <map>
-
 class ClearKeyDecryptor;
 
-class CryptoMetaData
-{
+class CryptoMetaData {
 public:
   CryptoMetaData() {}
 
-  explicit CryptoMetaData(const cdm::InputBuffer* aInputBuffer)
+  explicit CryptoMetaData(const GMPEncryptedBufferMetadata* aCrypto)
   {
-    Init(aInputBuffer);
+    Init(aCrypto);
   }
 
-  void Init(const cdm::InputBuffer* aInputBuffer)
+  void Init(const GMPEncryptedBufferMetadata* aCrypto)
   {
-    if (!aInputBuffer) {
+    if (!aCrypto) {
       assert(!IsValid());
       return;
     }
-
-    Assign(mKeyId, aInputBuffer->key_id, aInputBuffer->key_id_size);
-    Assign(mIV, aInputBuffer->iv, aInputBuffer->iv_size);
-
-    for (uint32_t i = 0; i < aInputBuffer->num_subsamples; ++i) {
-      const cdm::SubsampleEntry& subsample = aInputBuffer->subsamples[i];
-
-      mCipherBytes.push_back(subsample.cipher_bytes);
-      mClearBytes.push_back(subsample.clear_bytes);
-    }
+    Assign(mKeyId, aCrypto->KeyId(), aCrypto->KeyIdSize());
+    Assign(mIV, aCrypto->IV(), aCrypto->IVSize());
+    Assign(mClearBytes, aCrypto->ClearBytes(), aCrypto->NumSubsamples());
+    Assign(mCipherBytes, aCrypto->CipherBytes(), aCrypto->NumSubsamples());
   }
 
   bool IsValid() const {
     return !mKeyId.empty() &&
            !mIV.empty() &&
            !mCipherBytes.empty() &&
            !mClearBytes.empty();
   }
 
   size_t NumSubsamples() const {
     assert(mClearBytes.size() == mCipherBytes.size());
     return mClearBytes.size();
   }
 
   std::vector<uint8_t> mKeyId;
   std::vector<uint8_t> mIV;
-  std::vector<uint32_t> mClearBytes;
+  std::vector<uint16_t> mClearBytes;
   std::vector<uint32_t> mCipherBytes;
 };
 
 class ClearKeyDecryptionManager : public RefCounted
 {
 private:
   ClearKeyDecryptionManager();
   ~ClearKeyDecryptionManager();
@@ -91,20 +80,22 @@ public:
   const Key& GetDecryptionKey(const KeyId& aKeyId);
 
   // Create a decryptor for the given KeyId if one does not already exist.
   void InitKey(KeyId aKeyId, Key aKey);
   void ExpectKeyId(KeyId aKeyId);
   void ReleaseKeyId(KeyId aKeyId);
 
   // Decrypts buffer *in place*.
-  cdm::Status Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
-                      const CryptoMetaData& aMetadata);
-  cdm::Status Decrypt(std::vector<uint8_t>& aBuffer,
-                      const CryptoMetaData& aMetadata);
+  GMPErr Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
+                 const CryptoMetaData& aMetadata);
+  GMPErr Decrypt(std::vector<uint8_t>& aBuffer,
+                 const CryptoMetaData& aMetadata);
+
+  void Shutdown();
 
 private:
   bool IsExpectingKeyForKeyId(const KeyId& aKeyId) const;
 
   std::map<KeyId, ClearKeyDecryptor*> mDecryptors;
 };
 
 #endif // __ClearKeyDecryptionManager_h__
--- a/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp
@@ -10,159 +10,251 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "ClearKeyPersistence.h"
-
 #include "ClearKeyUtils.h"
 #include "ClearKeyStorage.h"
 #include "ClearKeySessionManager.h"
 #include "RefCounted.h"
 
+#include <stdint.h>
+#include <string.h>
+#include <set>
+#include <vector>
+#include <sstream>
 #include <assert.h>
-#include <stdint.h>
-#include <sstream>
-#include <string.h>
 
 using namespace std;
-using namespace cdm;
-
-void
-ClearKeyPersistence::ReadAllRecordsFromIndex(function<void()>&& aOnComplete) {
-  // Clear what we think the index file contains, we're about to read it again.
-  mPersistentSessionIds.clear();
 
-  // Hold a reference to the persistence manager, so it isn't released before
-  // we try and use it.
-  RefPtr<ClearKeyPersistence> self(this);
-  function<void(const uint8_t*, uint32_t)> onIndexSuccess =
-    [self, aOnComplete] (const uint8_t* data, uint32_t size)
-  {
-    CK_LOGD("ClearKeyPersistence: Loaded index file!");
-    const char* charData = (const char*)data;
+// Whether we've loaded the persistent session ids from GMPStorage yet.
+enum PersistentKeyState {
+  UNINITIALIZED,
+  LOADING,
+  LOADED
+};
+static PersistentKeyState sPersistentKeyState = UNINITIALIZED;
+
+// Set of session Ids of the persistent sessions created or residing in
+// storage.
+static set<uint32_t> sPersistentSessionIds;
+
+static vector<GMPTask*> sTasksBlockedOnSessionIdLoad;
 
-    stringstream ss(string(charData, charData + size));
-    string name;
-    while (getline(ss, name)) {
-      if (ClearKeyUtils::IsValidSessionId(name.data(), name.size())) {
-        self->mPersistentSessionIds.insert(atoi(name.c_str()));
+static void
+ReadAllRecordsFromIterator(GMPRecordIterator* aRecordIterator,
+                           void* aUserArg,
+                           GMPErr aStatus)
+{
+  assert(sPersistentKeyState == LOADING);
+  if (GMP_SUCCEEDED(aStatus)) {
+    // Extract the record names which are valid uint32_t's; they're
+    // the persistent session ids.
+    const char* name = nullptr;
+    uint32_t len = 0;
+    while (GMP_SUCCEEDED(aRecordIterator->GetName(&name, &len))) {
+      if (ClearKeyUtils::IsValidSessionId(name, len)) {
+        assert(name[len] == 0);
+        sPersistentSessionIds.insert(atoi(name));
       }
+      aRecordIterator->NextRecord();
     }
+  }
+  sPersistentKeyState = LOADED;
+  aRecordIterator->Close();
 
-    self->mPersistentKeyState = PersistentKeyState::LOADED;
-    aOnComplete();
-  };
-
-  function<void()> onIndexFailed =
-    [self, aOnComplete] ()
-  {
-    CK_LOGD("ClearKeyPersistence: Failed to load index file (it might not exist");
-    self->mPersistentKeyState = PersistentKeyState::LOADED;
-    aOnComplete();
-  };
-
-  string filename = "index";
-  ReadData(mHost, filename, move(onIndexSuccess), move(onIndexFailed));
+  for (size_t i = 0; i < sTasksBlockedOnSessionIdLoad.size(); i++) {
+    sTasksBlockedOnSessionIdLoad[i]->Run();
+    sTasksBlockedOnSessionIdLoad[i]->Destroy();
+  }
+  sTasksBlockedOnSessionIdLoad.clear();
 }
 
-void
-ClearKeyPersistence::WriteIndex() {
-  function <void()> onIndexSuccess =
-    [] ()
-  {
-    CK_LOGD("ClearKeyPersistence: Wrote index file");
-  };
-
-  function <void()> onIndexFail =
-    [] ()
-  {
-    CK_LOGD("ClearKeyPersistence: Failed to write index file (this is bad)");
-  };
-
-  stringstream ss;
-
-  for (const uint32_t& sessionId : mPersistentSessionIds) {
-    ss << sessionId;
-    ss << '\n';
-  }
-
-  string dataString = ss.str();
-  uint8_t* dataArray = (uint8_t*)dataString.data();
-  vector<uint8_t> data(dataArray, dataArray + dataString.size());
-
-  string filename = "index";
-  WriteData(mHost,
-            filename,
-            data,
-            move(onIndexSuccess),
-            move(onIndexFail));
-}
-
-
-ClearKeyPersistence::ClearKeyPersistence(Host_8* aHost)
+/* static */ void
+ClearKeyPersistence::EnsureInitialized()
 {
-  this->mHost = aHost;
-}
-
-void
-ClearKeyPersistence::EnsureInitialized(bool aPersistentStateAllowed,
-                                       function<void()>&& aOnInitialized)
-{
-  if (aPersistentStateAllowed &&
-      mPersistentKeyState == PersistentKeyState::UNINITIALIZED) {
-    mPersistentKeyState = LOADING;
-    ReadAllRecordsFromIndex(move(aOnInitialized));
-  } else {
-    mPersistentKeyState = PersistentKeyState::LOADED;
-    aOnInitialized();
+  if (sPersistentKeyState == UNINITIALIZED) {
+    sPersistentKeyState = LOADING;
+    if (GMP_FAILED(EnumRecordNames(&ReadAllRecordsFromIterator))) {
+      sPersistentKeyState = LOADED;
+    }
   }
 }
 
-bool ClearKeyPersistence::IsLoaded() const
-{
-  return mPersistentKeyState == PersistentKeyState::LOADED;
-}
-
-string
-ClearKeyPersistence::GetNewSessionId(SessionType aSessionType)
+/* static */ string
+ClearKeyPersistence::GetNewSessionId(GMPSessionType aSessionType)
 {
   static uint32_t sNextSessionId = 1;
 
   // Ensure we don't re-use a session id that was persisted.
-  while (Contains(mPersistentSessionIds, sNextSessionId)) {
+  while (Contains(sPersistentSessionIds, sNextSessionId)) {
     sNextSessionId++;
   }
 
   string sessionId;
   stringstream ss;
   ss << sNextSessionId;
   ss >> sessionId;
 
-  if (aSessionType == SessionType::kPersistentLicense) {
-    mPersistentSessionIds.insert(sNextSessionId);
-
-    // Save the updated index file.
-    WriteIndex();
+  if (aSessionType == kGMPPersistentSession) {
+    sPersistentSessionIds.insert(sNextSessionId);
   }
 
   sNextSessionId++;
 
   return sessionId;
 }
 
-bool
-ClearKeyPersistence::IsPersistentSessionId(const string& aSessionId)
+
+class CreateSessionTask : public GMPTask {
+public:
+  CreateSessionTask(ClearKeySessionManager* aTarget,
+                    uint32_t aCreateSessionToken,
+                    uint32_t aPromiseId,
+                    const string& aInitDataType,
+                    const uint8_t* aInitData,
+                    uint32_t aInitDataSize,
+                    GMPSessionType aSessionType)
+    : mTarget(aTarget)
+    , mCreateSessionToken(aCreateSessionToken)
+    , mPromiseId(aPromiseId)
+    , mInitDataType(aInitDataType)
+    , mSessionType(aSessionType)
+  {
+    mInitData.insert(mInitData.end(),
+                     aInitData,
+                     aInitData + aInitDataSize);
+  }
+  virtual void Run() override {
+    mTarget->CreateSession(mCreateSessionToken,
+                           mPromiseId,
+                           mInitDataType.c_str(),
+                           mInitDataType.size(),
+                           &mInitData.front(),
+                           mInitData.size(),
+                           mSessionType);
+  }
+  virtual void Destroy() override {
+    delete this;
+  }
+private:
+  RefPtr<ClearKeySessionManager> mTarget;
+  uint32_t mCreateSessionToken;
+  uint32_t mPromiseId;
+  const string mInitDataType;
+  vector<uint8_t> mInitData;
+  GMPSessionType mSessionType;
+};
+
+
+/* static */ bool
+ClearKeyPersistence::DeferCreateSessionIfNotReady(ClearKeySessionManager* aInstance,
+                                                  uint32_t aCreateSessionToken,
+                                                  uint32_t aPromiseId,
+                                                  const string& aInitDataType,
+                                                  const uint8_t* aInitData,
+                                                  uint32_t aInitDataSize,
+                                                  GMPSessionType aSessionType)
 {
-  return Contains(mPersistentSessionIds, atoi(aSessionId.c_str()));
+  if (sPersistentKeyState >= LOADED)  {
+    return false;
+  }
+  GMPTask* t = new CreateSessionTask(aInstance,
+                                     aCreateSessionToken,
+                                     aPromiseId,
+                                     aInitDataType,
+                                     aInitData,
+                                     aInitDataSize,
+                                     aSessionType);
+  sTasksBlockedOnSessionIdLoad.push_back(t);
+  return true;
 }
 
-void
-ClearKeyPersistence::PersistentSessionRemoved(string& aSessionId)
+class LoadSessionTask : public GMPTask {
+public:
+  LoadSessionTask(ClearKeySessionManager* aTarget,
+                  uint32_t aPromiseId,
+                  const char* aSessionId,
+                  uint32_t aSessionIdLength)
+    : mTarget(aTarget)
+    , mPromiseId(aPromiseId)
+    , mSessionId(aSessionId, aSessionId + aSessionIdLength)
+  {
+  }
+  virtual void Run() override {
+    mTarget->LoadSession(mPromiseId,
+                         mSessionId.c_str(),
+                         mSessionId.size());
+  }
+  virtual void Destroy() override {
+    delete this;
+  }
+private:
+  RefPtr<ClearKeySessionManager> mTarget;
+  uint32_t mPromiseId;
+  string mSessionId;
+};
+
+/* static */ bool
+ClearKeyPersistence::DeferLoadSessionIfNotReady(ClearKeySessionManager* aInstance,
+                                                uint32_t aPromiseId,
+                                                const char* aSessionId,
+                                                uint32_t aSessionIdLength)
 {
-  mPersistentSessionIds.erase(atoi(aSessionId.c_str()));
+  if (sPersistentKeyState >= LOADED)  {
+    return false;
+  }
+  GMPTask* t = new LoadSessionTask(aInstance,
+                                   aPromiseId,
+                                   aSessionId,
+                                   aSessionIdLength);
+  sTasksBlockedOnSessionIdLoad.push_back(t);
+  return true;
+}
+
+/* static */ bool
+ClearKeyPersistence::IsPersistentSessionId(const string& aSessionId)
+{
+  return Contains(sPersistentSessionIds, atoi(aSessionId.c_str()));
+}
+
+class LoadSessionFromKeysTask : public ReadContinuation {
+public:
+  LoadSessionFromKeysTask(ClearKeySessionManager* aTarget,
+                          const string& aSessionId,
+                          uint32_t aPromiseId)
+    : mTarget(aTarget)
+    , mSessionId(aSessionId)
+    , mPromiseId(aPromiseId)
+  {
+  }
 
-  // Update the index file.
-  WriteIndex();
+  virtual void ReadComplete(GMPErr aStatus,
+                            const uint8_t* aData,
+                            uint32_t aLength) override
+  {
+    mTarget->PersistentSessionDataLoaded(aStatus, mPromiseId, mSessionId, aData, aLength);
+  }
+private:
+  RefPtr<ClearKeySessionManager> mTarget;
+  string mSessionId;
+  uint32_t mPromiseId;
+};
+
+/* static */ void
+ClearKeyPersistence::LoadSessionData(ClearKeySessionManager* aInstance,
+                                     const string& aSid,
+                                     uint32_t aPromiseId)
+{
+  LoadSessionFromKeysTask* loadTask =
+    new LoadSessionFromKeysTask(aInstance, aSid, aPromiseId);
+  ReadData(aSid, loadTask);
 }
+
+/* static */ void
+ClearKeyPersistence::PersistentSessionRemoved(const string& aSessionId)
+{
+  sPersistentSessionIds.erase(atoi(aSessionId.c_str()));
+}
--- a/media/gmp-clearkey/0.1/ClearKeyPersistence.h
+++ b/media/gmp-clearkey/0.1/ClearKeyPersistence.h
@@ -12,56 +12,42 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef __ClearKeyPersistence_h__
 #define __ClearKeyPersistence_h__
 
-// This include is required in order for content_decryption_module to work
-// on Unix systems.
-#include "stddef.h"
-#include "content_decryption_module.h"
-#include "RefCounted.h"
-
-#include <functional>
-#include <set>
 #include <string>
-#include <vector>
-
+#include "gmp-api/gmp-decryption.h"
 
 class ClearKeySessionManager;
 
-// Whether we've loaded the persistent session ids yet.
-enum PersistentKeyState {
-  UNINITIALIZED,
-  LOADING,
-  LOADED
-};
+class ClearKeyPersistence {
+public:
+  static void EnsureInitialized();
 
-class ClearKeyPersistence : public RefCounted
-{
-public:
-  explicit ClearKeyPersistence(cdm::Host_8* aHost);
-
-  void EnsureInitialized(bool aPersistentStateAllowed,
-                         std::function<void()>&& aOnInitialized);
+  static std::string GetNewSessionId(GMPSessionType aSessionType);
 
-  bool IsLoaded() const;
-
-  std::string GetNewSessionId(cdm::SessionType aSessionType);
-
-  bool IsPersistentSessionId(const std::string& aSid);
+  static bool DeferCreateSessionIfNotReady(ClearKeySessionManager* aInstance,
+                                           uint32_t aCreateSessionToken,
+                                           uint32_t aPromiseId,
+                                           const std::string& aInitDataType,
+                                           const uint8_t* aInitData,
+                                           uint32_t aInitDataSize,
+                                           GMPSessionType aSessionType);
 
-  void PersistentSessionRemoved(std::string& aSid);
-private:
-  cdm::Host_8* mHost = nullptr;
+  static bool DeferLoadSessionIfNotReady(ClearKeySessionManager* aInstance,
+                                         uint32_t aPromiseId,
+                                         const char* aSessionId,
+                                         uint32_t aSessionIdLength);
 
-  PersistentKeyState mPersistentKeyState = PersistentKeyState::UNINITIALIZED;
+  static bool IsPersistentSessionId(const std::string& aSid);
 
-  std::set<uint32_t> mPersistentSessionIds;
+  static void LoadSessionData(ClearKeySessionManager* aInstance,
+                              const std::string& aSid,
+                              uint32_t aPromiseId);
 
-  void ReadAllRecordsFromIndex(std::function<void()>&& aOnComplete);
-  void WriteIndex();
+  static void PersistentSessionRemoved(const std::string& aSid);
 };
 
 #endif // __ClearKeyPersistence_h__
--- a/media/gmp-clearkey/0.1/ClearKeySession.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeySession.cpp
@@ -15,64 +15,78 @@
  */
 
 #include "BigEndian.h"
 #include "ClearKeyDecryptionManager.h"
 #include "ClearKeySession.h"
 #include "ClearKeyUtils.h"
 #include "ClearKeyStorage.h"
 #include "psshparser/PsshParser.h"
-
+#include "gmp-task-utils.h"
+#include "gmp-api/gmp-decryption.h"
 #include <assert.h>
 #include <string.h>
 
 using namespace mozilla;
-using namespace cdm;
-using namespace std;
 
 ClearKeySession::ClearKeySession(const std::string& aSessionId,
-                                 SessionType aSessionType)
+                                 GMPDecryptorCallback* aCallback,
+                                 GMPSessionType aSessionType)
   : mSessionId(aSessionId)
+  , mCallback(aCallback)
   , mSessionType(aSessionType)
 {
   CK_LOGD("ClearKeySession ctor %p", this);
 }
 
 ClearKeySession::~ClearKeySession()
 {
   CK_LOGD("ClearKeySession dtor %p", this);
+
+  std::vector<GMPMediaKeyInfo> key_infos;
+  for (const KeyId& keyId : mKeyIds) {
+    assert(ClearKeyDecryptionManager::Get()->HasSeenKeyId(keyId));
+    ClearKeyDecryptionManager::Get()->ReleaseKeyId(keyId);
+    key_infos.push_back(GMPMediaKeyInfo(&keyId[0], keyId.size(), kGMPUnknown));
+  }
+  mCallback->BatchedKeyStatusChanged(&mSessionId[0], mSessionId.size(),
+                                     key_infos.data(), key_infos.size());
 }
 
-bool
-ClearKeySession::Init(InitDataType aInitDataType,
-                      const uint8_t* aInitData,
-                      uint32_t aInitDataSize)
+void
+ClearKeySession::Init(uint32_t aCreateSessionToken,
+                      uint32_t aPromiseId,
+                      const std::string& aInitDataType,
+                      const uint8_t* aInitData, uint32_t aInitDataSize)
 {
   CK_LOGD("ClearKeySession::Init");
 
-  if (aInitDataType == InitDataType::kCenc) {
+  if (aInitDataType == "cenc") {
     ParseCENCInitData(aInitData, aInitDataSize, mKeyIds);
-  } else if (aInitDataType == InitDataType::kKeyIds) {
+  } else if (aInitDataType == "keyids") {
     ClearKeyUtils::ParseKeyIdsInitData(aInitData, aInitDataSize, mKeyIds);
-  } else if (aInitDataType == InitDataType::kWebM &&
-             aInitDataSize <= kMaxWebmInitDataSize) {
+  } else if (aInitDataType == "webm" && aInitDataSize <= kMaxWebmInitDataSize) {
     // "webm" initData format is simply the raw bytes of the keyId.
     vector<uint8_t> keyId;
     keyId.assign(aInitData, aInitData+aInitDataSize);
     mKeyIds.push_back(keyId);
   }
 
   if (!mKeyIds.size()) {
-    return false;
+    const char message[] = "Couldn't parse init data";
+    mCallback->RejectPromise(aPromiseId, kGMPTypeError, message, strlen(message));
+    return;
   }
 
-  return true;
+  mCallback->SetSessionId(aCreateSessionToken, &mSessionId[0], mSessionId.length());
+
+  mCallback->ResolvePromise(aPromiseId);
 }
 
-SessionType
+GMPSessionType
 ClearKeySession::Type() const
 {
   return mSessionType;
 }
 
 void
 ClearKeySession::AddKeyId(const KeyId& aKeyId)
 {
--- a/media/gmp-clearkey/0.1/ClearKeySession.h
+++ b/media/gmp-clearkey/0.1/ClearKeySession.h
@@ -13,43 +13,46 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef __ClearKeySession_h__
 #define __ClearKeySession_h__
 
 #include "ClearKeyUtils.h"
-// This include is required in order for content_decryption_module to work
-// on Unix systems.
-#include "stddef.h"
-#include "content_decryption_module.h"
+#include "gmp-api/gmp-decryption.h"
 
-#include <string>
-#include <vector>
+class GMPBuffer;
+class GMPDecryptorCallback;
+class GMPDecryptorHost;
+class GMPEncryptedBufferMetadata;
 
 class ClearKeySession
 {
 public:
   explicit ClearKeySession(const std::string& aSessionId,
-                           cdm::SessionType aSessionType);
+                           GMPDecryptorCallback* aCallback,
+                           GMPSessionType aSessionType);
 
   ~ClearKeySession();
 
   const std::vector<KeyId>& GetKeyIds() const { return mKeyIds; }
 
-  bool Init(cdm::InitDataType aInitDataType,
+  void Init(uint32_t aCreateSessionToken,
+            uint32_t aPromiseId,
+            const string& aInitDataType,
             const uint8_t* aInitData, uint32_t aInitDataSize);
 
-  cdm::SessionType Type() const;
+  GMPSessionType Type() const;
 
   void AddKeyId(const KeyId& aKeyId);
 
   const std::string& Id() const { return mSessionId; }
 
 private:
   const std::string mSessionId;
   std::vector<KeyId> mKeyIds;
 
-  const cdm::SessionType mSessionType;
+  GMPDecryptorCallback* mCallback;
+  const GMPSessionType mSessionType;
 };
 
 #endif // __ClearKeySession_h__
--- a/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp
@@ -9,151 +9,98 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
 #include "ClearKeyDecryptionManager.h"
 #include "ClearKeySessionManager.h"
 #include "ClearKeyUtils.h"
 #include "ClearKeyStorage.h"
 #include "ClearKeyPersistence.h"
-// This include is required in order for content_decryption_module to work
-// on Unix systems.
-#include "stddef.h"
-#include "content_decryption_module.h"
-#include "psshparser/PsshParser.h"
-
+#include "gmp-task-utils.h"
 #include <assert.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
 
 using namespace std;
-using namespace cdm;
 
-ClearKeySessionManager::ClearKeySessionManager(Host_8* aHost)
+ClearKeySessionManager::ClearKeySessionManager()
   : mDecryptionManager(ClearKeyDecryptionManager::Get())
 {
   CK_LOGD("ClearKeySessionManager ctor %p", this);
   AddRef();
 
-  mHost = aHost;
-  mPersistence = new ClearKeyPersistence(mHost);
+  if (GetPlatform()->createthread(&mThread) != GMPNoErr) {
+    CK_LOGD("failed to create thread in clearkey cdm");
+    mThread = nullptr;
+  }
 }
 
 ClearKeySessionManager::~ClearKeySessionManager()
 {
   CK_LOGD("ClearKeySessionManager dtor %p", this);
 }
 
 void
-ClearKeySessionManager::Init(bool aDistinctiveIdentifierAllowed,
+ClearKeySessionManager::Init(GMPDecryptorCallback* aCallback,
+                             bool aDistinctiveIdentifierAllowed,
                              bool aPersistentStateAllowed)
 {
   CK_LOGD("ClearKeySessionManager::Init");
-
-  RefPtr<ClearKeySessionManager> self(this);
-  function<void()> onPersistentStateLoaded =
-    [self] ()
-  {
-    while (!self->mDeferredInitialize.empty()) {
-      function<void()> func = self->mDeferredInitialize.front();
-      self->mDeferredInitialize.pop();
-
-      func();
-    }
-  };
-
-  mPersistence->EnsureInitialized(aPersistentStateAllowed,
-                                  move(onPersistentStateLoaded));
+  mCallback = aCallback;
+  ClearKeyPersistence::EnsureInitialized();
 }
 
 void
-ClearKeySessionManager::CreateSession(uint32_t aPromiseId,
-                                      InitDataType aInitDataType,
+ClearKeySessionManager::CreateSession(uint32_t aCreateSessionToken,
+                                      uint32_t aPromiseId,
+                                      const char* aInitDataType,
+                                      uint32_t aInitDataTypeSize,
                                       const uint8_t* aInitData,
                                       uint32_t aInitDataSize,
-                                      SessionType aSessionType)
+                                      GMPSessionType aSessionType)
 {
-  // Copy the init data so it is correctly captured by the lambda
-  vector<uint8_t> initData(aInitData, aInitData + aInitDataSize);
+  CK_LOGD("ClearKeySessionManager::CreateSession type:%s", aInitDataType);
 
-  RefPtr<ClearKeySessionManager> self(this);
-  function<void()> deferrer =
-    [self, aPromiseId, aInitDataType, initData, aSessionType] ()
-  {
-    self->CreateSession(aPromiseId,
-                        aInitDataType,
-                        initData.data(),
-                        initData.size(),
-                        aSessionType);
-  };
-
-  // If we haven't loaded, don't do this yet
-  if (MaybeDeferTillInitialized(deferrer)) {
+  string initDataType(aInitDataType, aInitDataType + aInitDataTypeSize);
+  // initDataType must be "cenc", "keyids", or "webm".
+  if (initDataType != "cenc" &&
+      initDataType != "keyids" &&
+      initDataType != "webm") {
+    string message = "'" + initDataType + "' is an initDataType unsupported by ClearKey";
+    mCallback->RejectPromise(aPromiseId, kGMPNotSupportedError,
+                             message.c_str(), message.size());
     return;
   }
 
-  CK_LOGD("ClearKeySessionManager::CreateSession type:%s", aInitDataType);
-
-  CK_LOGARRAY("ClearKeySessionManager::CreateSession initdata: ",
-              aInitData,
-              aInitDataSize);
-
-  // If 'DecryptingComplete' has been called mHost will be null so we can't
-  // won't be able to resolve our promise
-  if (!mHost) {
-    CK_LOGD("ClearKeySessionManager::CreateSession: mHost is nullptr")
+  if (ClearKeyPersistence::DeferCreateSessionIfNotReady(this,
+                                                        aCreateSessionToken,
+                                                        aPromiseId,
+                                                        initDataType,
+                                                        aInitData,
+                                                        aInitDataSize,
+                                                        aSessionType)) {
     return;
   }
 
-  // initDataType must be "cenc", "keyids", or "webm".
-  if (aInitDataType != InitDataType::kCenc &&
-      aInitDataType != InitDataType::kKeyIds &&
-      aInitDataType != InitDataType::kWebM) {
-
-    string message = "initDataType is not supported by ClearKey";
-    mHost->OnRejectPromise(aPromiseId,
-                           Error::kNotSupportedError,
-                           0,
-                           message.c_str(),
-                           message.size());
-
-    return;
-  }
-
-  string sessionId = mPersistence->GetNewSessionId(aSessionType);
+  string sessionId = ClearKeyPersistence::GetNewSessionId(aSessionType);
   assert(mSessions.find(sessionId) == mSessions.end());
 
-  ClearKeySession* session = new ClearKeySession(sessionId,
-                                                 aSessionType);
-
-  if (!session->Init(aInitDataType, aInitData, aInitDataSize)) {
-
-    CK_LOGD("Failed to initialize session: %s", sessionId.c_str());
-
-    const static char* message = "Failed to initialize session";
-    mHost->OnRejectPromise(aPromiseId,
-                           Error::kUnknownError,
-                           0,
-                           message,
-                           strlen(message));
-
-    return;
-  }
-
+  ClearKeySession* session = new ClearKeySession(sessionId, mCallback, aSessionType);
+  session->Init(aCreateSessionToken, aPromiseId, initDataType, aInitData, aInitDataSize);
   mSessions[sessionId] = session;
 
   const vector<KeyId>& sessionKeys = session->GetKeyIds();
   vector<KeyId> neededKeys;
-
   for (auto it = sessionKeys.begin(); it != sessionKeys.end(); it++) {
     // Need to request this key ID from the client. We always send a key
     // request, whether or not another session has sent a request with the same
     // key ID. Otherwise a script can end up waiting for another script to
     // respond to the request (which may not necessarily happen).
     neededKeys.push_back(*it);
     mDecryptionManager->ExpectKeyId(*it);
   }
@@ -161,120 +108,73 @@ ClearKeySessionManager::CreateSession(ui
   if (neededKeys.empty()) {
     CK_LOGD("No keys needed from client.");
     return;
   }
 
   // Send a request for needed key data.
   string request;
   ClearKeyUtils::MakeKeyRequest(neededKeys, request, aSessionType);
-
-  // Resolve the promise with the new session information.
-  mHost->OnResolveNewSessionPromise(aPromiseId,
-                                    sessionId.c_str(),
-                                    sessionId.size());
-
-  mHost->OnSessionMessage(sessionId.c_str(),
-                          sessionId.size(),
-                          MessageType::kLicenseRequest,
-                          request.c_str(),
-                          request.size(),
-                          nullptr,
-                          0);
+  mCallback->SessionMessage(&sessionId[0], sessionId.length(),
+                            kGMPLicenseRequest,
+                            (uint8_t*)&request[0], request.length());
 }
 
 void
 ClearKeySessionManager::LoadSession(uint32_t aPromiseId,
                                     const char* aSessionId,
                                     uint32_t aSessionIdLength)
 {
-  // Copy the sessionId into a string so the lambda captures it properly.
-  string sessionId(aSessionId, aSessionId + aSessionIdLength);
+  CK_LOGD("ClearKeySessionManager::LoadSession");
 
-  // Hold a reference to the SessionManager so that it isn't released before
-  // we try to use it.
-  RefPtr<ClearKeySessionManager> self(this);
-  function<void()> deferrer =
-    [self, aPromiseId, sessionId] ()
-  {
-    self->LoadSession(aPromiseId, sessionId.data(), sessionId.size());
-  };
-
-  if (MaybeDeferTillInitialized(deferrer)) {
+  if (!ClearKeyUtils::IsValidSessionId(aSessionId, aSessionIdLength)) {
+    mCallback->ResolveLoadSessionPromise(aPromiseId, false);
     return;
   }
 
-  CK_LOGD("ClearKeySessionManager::LoadSession");
-
-  // If the SessionManager has been shutdown mHost will be null and we won't
-  // be able to resolve the promise.
-  if (!mHost) {
+  if (ClearKeyPersistence::DeferLoadSessionIfNotReady(this,
+                                                      aPromiseId,
+                                                      aSessionId,
+                                                      aSessionIdLength)) {
     return;
   }
 
-  if (!ClearKeyUtils::IsValidSessionId(aSessionId, aSessionIdLength)) {
-    mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0);
-    return;
-  }
-
-  if (!mPersistence->IsPersistentSessionId(sessionId)) {
-    mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0);
+  string sid(aSessionId, aSessionId + aSessionIdLength);
+  if (!ClearKeyPersistence::IsPersistentSessionId(sid)) {
+    mCallback->ResolveLoadSessionPromise(aPromiseId, false);
     return;
   }
 
-  function<void(const uint8_t*, uint32_t)> success =
-    [self, sessionId, aPromiseId] (const uint8_t* data, uint32_t size)
-  {
-    self->PersistentSessionDataLoaded(aPromiseId,
-                                      sessionId,
-                                      data,
-                                      size);
-  };
-
-  function<void()> failure = [self, sessionId, aPromiseId] {
-    if (!self->mHost) {
-      return;
-    }
-    // As per the API described in ContentDecryptionModule_8
-    self->mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0);
-  };
-
-  ReadData(mHost, sessionId, move(success), move(failure));
+  // Callsback PersistentSessionDataLoaded with results...
+  ClearKeyPersistence::LoadSessionData(this, sid, aPromiseId);
 }
 
 void
-ClearKeySessionManager::PersistentSessionDataLoaded(uint32_t aPromiseId,
+ClearKeySessionManager::PersistentSessionDataLoaded(GMPErr aStatus,
+                                                    uint32_t aPromiseId,
                                                     const string& aSessionId,
                                                     const uint8_t* aKeyData,
                                                     uint32_t aKeyDataSize)
 {
   CK_LOGD("ClearKeySessionManager::PersistentSessionDataLoaded");
-
-  // Check that the SessionManager has not been shut down before we try and
-  // resolve any promises.
-  if (!mHost) {
-    return;
-  }
-
-  if (Contains(mSessions, aSessionId) ||
+  if (GMP_FAILED(aStatus) ||
+      Contains(mSessions, aSessionId) ||
       (aKeyDataSize % (2 * CENC_KEY_LEN)) != 0) {
-
-    // As per the instructions in ContentDecryptionModule_8
-    mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0);
+    mCallback->ResolveLoadSessionPromise(aPromiseId, false);
     return;
   }
 
   ClearKeySession* session = new ClearKeySession(aSessionId,
-                                                 SessionType::kPersistentLicense);
-
+                                                 mCallback,
+                                                 kGMPPersistentSession);
   mSessions[aSessionId] = session;
 
   uint32_t numKeys = aKeyDataSize / (2 * CENC_KEY_LEN);
 
-  vector<KeyInformation> keyInfos;
+  vector<GMPMediaKeyInfo> key_infos;
   vector<KeyIdPair> keyPairs;
   for (uint32_t i = 0; i < numKeys; i ++) {
     const uint8_t* base = aKeyData + 2 * CENC_KEY_LEN * i;
 
     KeyIdPair keyPair;
 
     keyPair.mKeyId = KeyId(base, base + CENC_KEY_LEN);
     assert(keyPair.mKeyId.size() == CENC_KEY_LEN);
@@ -282,173 +182,91 @@ ClearKeySessionManager::PersistentSessio
     keyPair.mKey = Key(base + CENC_KEY_LEN, base + 2 * CENC_KEY_LEN);
     assert(keyPair.mKey.size() == CENC_KEY_LEN);
 
     session->AddKeyId(keyPair.mKeyId);
 
     mDecryptionManager->ExpectKeyId(keyPair.mKeyId);
     mDecryptionManager->InitKey(keyPair.mKeyId, keyPair.mKey);
     mKeyIds.insert(keyPair.mKey);
-    keyPairs.push_back(keyPair);
-
-    KeyInformation keyInfo = KeyInformation();
-    keyInfo.key_id = &keyPairs.back().mKeyId[0];
-    keyInfo.key_id_size = keyPair.mKeyId.size();
-    keyInfo.status = KeyStatus::kUsable;
-
-    keyInfos.push_back(keyInfo);
-  }
 
-  mHost->OnSessionKeysChange(&aSessionId[0],
-                             aSessionId.size(),
-                             true,
-                             keyInfos.data(),
-                             keyInfos.size());
+    keyPairs.push_back(keyPair);
+    key_infos.push_back(GMPMediaKeyInfo(&keyPairs[i].mKeyId[0],
+                                        keyPairs[i].mKeyId.size(),
+                                        kGMPUsable));
+  }
+  mCallback->BatchedKeyStatusChanged(&aSessionId[0], aSessionId.size(),
+                                     key_infos.data(), key_infos.size());
 
-  mHost->OnResolveNewSessionPromise(aPromiseId,
-                                    aSessionId.c_str(),
-                                    aSessionId.size());
+  mCallback->ResolveLoadSessionPromise(aPromiseId, true);
 }
 
 void
 ClearKeySessionManager::UpdateSession(uint32_t aPromiseId,
                                       const char* aSessionId,
                                       uint32_t aSessionIdLength,
                                       const uint8_t* aResponse,
                                       uint32_t aResponseSize)
 {
-  // Copy the method arguments so we can capture them in the lambda
+  CK_LOGD("ClearKeySessionManager::UpdateSession");
   string sessionId(aSessionId, aSessionId + aSessionIdLength);
-  vector<uint8_t> response(aResponse, aResponse + aResponseSize);
-
-  // Hold  a reference to the SessionManager so it isn't released before we
-  // callback.
-  RefPtr<ClearKeySessionManager> self(this);
-  function<void()> deferrer =
-    [self, aPromiseId, sessionId, response] ()
-  {
-    self->UpdateSession(aPromiseId,
-                        sessionId.data(),
-                        sessionId.size(),
-                        response.data(),
-                        response.size());
-  };
-
-  // If we haven't fully loaded, defer calling this method
-  if (MaybeDeferTillInitialized(deferrer)) {
-    return;
-  }
-
-  // Make sure the SessionManager has not been shutdown before we try and
-  // resolve any promises.
-  if (!mHost) {
-    return;
-  }
-
-  CK_LOGD("ClearKeySessionManager::UpdateSession");
-  CK_LOGD("Updating session: %s", sessionId.c_str());
 
   auto itr = mSessions.find(sessionId);
   if (itr == mSessions.end() || !(itr->second)) {
     CK_LOGW("ClearKey CDM couldn't resolve session ID in UpdateSession.");
-    CK_LOGD("Unable to find session: %s", sessionId.c_str());
-    mHost->OnRejectPromise(aPromiseId,
-                           Error::kInvalidAccessError,
-                           0,
-                           nullptr,
-                           0);
-
+    mCallback->RejectPromise(aPromiseId, kGMPNotFoundError, nullptr, 0);
     return;
   }
   ClearKeySession* session = itr->second;
 
   // Verify the size of session response.
   if (aResponseSize >= kMaxSessionResponseLength) {
     CK_LOGW("Session response size is not within a reasonable size.");
-    CK_LOGD("Failed to parse response for session %s", sessionId.c_str());
-
-    mHost->OnRejectPromise(aPromiseId,
-                           Error::kInvalidAccessError,
-                           0,
-                           nullptr,
-                           0);
-
+    mCallback->RejectPromise(aPromiseId, kGMPTypeError, nullptr, 0);
     return;
   }
 
   // Parse the response for any (key ID, key) pairs.
   vector<KeyIdPair> keyPairs;
-  if (!ClearKeyUtils::ParseJWK(aResponse,
-                               aResponseSize,
-                               keyPairs,
-                               session->Type())) {
+  if (!ClearKeyUtils::ParseJWK(aResponse, aResponseSize, keyPairs, session->Type())) {
     CK_LOGW("ClearKey CDM failed to parse JSON Web Key.");
-
-    mHost->OnRejectPromise(aPromiseId,
-                           Error::kInvalidAccessError,
-                           0,
-                           nullptr,
-                           0);
-
+    mCallback->RejectPromise(aPromiseId, kGMPTypeError, nullptr, 0);
     return;
   }
 
-  vector<KeyInformation> keyInfos;
+  vector<GMPMediaKeyInfo> key_infos;
   for (size_t i = 0; i < keyPairs.size(); i++) {
     KeyIdPair& keyPair = keyPairs[i];
     mDecryptionManager->InitKey(keyPair.mKeyId, keyPair.mKey);
     mKeyIds.insert(keyPair.mKeyId);
-
-    KeyInformation keyInfo = KeyInformation();
-    keyInfo.key_id = &keyPair.mKeyId[0];
-    keyInfo.key_id_size = keyPair.mKeyId.size();
-    keyInfo.status = KeyStatus::kUsable;
-
-    keyInfos.push_back(keyInfo);
+    key_infos.push_back(GMPMediaKeyInfo(&keyPair.mKeyId[0],
+                                        keyPair.mKeyId.size(),
+                                        kGMPUsable));
   }
+  mCallback->BatchedKeyStatusChanged(aSessionId, aSessionIdLength,
+                                     key_infos.data(), key_infos.size());
 
-  mHost->OnSessionKeysChange(aSessionId,
-                             aSessionIdLength,
-                             true,
-                             keyInfos.data(),
-                             keyInfos.size());
-
-  if (session->Type() != SessionType::kPersistentLicense) {
-    mHost->OnResolvePromise(aPromiseId);
+  if (session->Type() != kGMPPersistentSession) {
+    mCallback->ResolvePromise(aPromiseId);
     return;
   }
 
   // Store the keys on disk. We store a record whose name is the sessionId,
   // and simply append each keyId followed by its key.
   vector<uint8_t> keydata;
   Serialize(session, keydata);
-
-  function<void()> resolve = [self, aPromiseId] ()
-  {
-    if (!self->mHost) {
-      return;
-    }
-    self->mHost->OnResolvePromise(aPromiseId);
-  };
-
-  function<void()> reject = [self, aPromiseId] ()
-  {
-    if (!self->mHost) {
-      return;
-    }
-
-    static const char* message = "Couldn't store cenc key init data";
-    self->mHost->OnRejectPromise(aPromiseId,
-                                 Error::kInvalidStateError,
-                                 0,
-                                 message,
-                                 strlen(message));
-  };
-
-  WriteData(mHost, sessionId, keydata, move(resolve), move(reject));
+  GMPTask* resolve = WrapTask(mCallback, &GMPDecryptorCallback::ResolvePromise, aPromiseId);
+  static const char* message = "Couldn't store cenc key init data";
+  GMPTask* reject = WrapTask(mCallback,
+                             &GMPDecryptorCallback::RejectPromise,
+                             aPromiseId,
+                             kGMPInvalidStateError,
+                             message,
+                             strlen(message));
+  StoreData(sessionId, keydata, resolve, reject);
 }
 
 void
 ClearKeySessionManager::Serialize(const ClearKeySession* aSession,
                                   std::vector<uint8_t>& aOutKeyData)
 {
   const std::vector<KeyId>& keyIds = aSession->GetKeyIds();
   for (size_t i = 0; i < keyIds.size(); i++) {
@@ -464,205 +282,137 @@ ClearKeySessionManager::Serialize(const 
   }
 }
 
 void
 ClearKeySessionManager::CloseSession(uint32_t aPromiseId,
                                      const char* aSessionId,
                                      uint32_t aSessionIdLength)
 {
-  // Copy the sessionId into a string so we capture it properly.
-  string sessionId(aSessionId, aSessionId + aSessionIdLength);
-  // Hold a reference to the session manager, so it doesn't get deleted
-  // before we need to use it.
-  RefPtr<ClearKeySessionManager> self(this);
-  function<void()> deferrer =
-    [self, aPromiseId, sessionId] ()
-  {
-    self->CloseSession(aPromiseId, sessionId.data(), sessionId.size());
-  };
-
-  // If we haven't loaded, call this method later.
-  if (MaybeDeferTillInitialized(deferrer)) {
-    return;
-  }
-
   CK_LOGD("ClearKeySessionManager::CloseSession");
 
-  // If DecryptingComplete has been called mHost will be null and we won't
-  // be able to resolve our promise.
-  if (!mHost) {
-    return;
-  }
-
+  string sessionId(aSessionId, aSessionId + aSessionIdLength);
   auto itr = mSessions.find(sessionId);
   if (itr == mSessions.end()) {
     CK_LOGW("ClearKey CDM couldn't close non-existent session.");
-    mHost->OnRejectPromise(aPromiseId,
-                           Error::kInvalidAccessError,
-                           0,
-                           nullptr,
-                           0);
-
+    mCallback->RejectPromise(aPromiseId, kGMPNotFoundError, nullptr, 0);
     return;
   }
 
   ClearKeySession* session = itr->second;
   assert(session);
 
   ClearInMemorySessionData(session);
-
-  mHost->OnSessionClosed(aSessionId, aSessionIdLength);
-  mHost->OnResolvePromise(aPromiseId);
+  mCallback->SessionClosed(aSessionId, aSessionIdLength);
+  mCallback->ResolvePromise(aPromiseId);
 }
 
 void
 ClearKeySessionManager::ClearInMemorySessionData(ClearKeySession* aSession)
 {
   mSessions.erase(aSession->Id());
   delete aSession;
 }
 
 void
 ClearKeySessionManager::RemoveSession(uint32_t aPromiseId,
                                       const char* aSessionId,
                                       uint32_t aSessionIdLength)
 {
-  // Copy the sessionId into a string so it can be captured for the lambda.
+  CK_LOGD("ClearKeySessionManager::RemoveSession");
   string sessionId(aSessionId, aSessionId + aSessionIdLength);
-
-  // Hold a reference to the SessionManager, so it isn't released before we
-  // try and use it.
-  RefPtr<ClearKeySessionManager> self(this);
-  function<void()> deferrer =
-    [self, aPromiseId, sessionId] ()
-  {
-    self->RemoveSession(aPromiseId, sessionId.data(), sessionId.size());
-  };
-
-  // If we haven't fully loaded, defer calling this method.
-  if (MaybeDeferTillInitialized(deferrer)) {
-    return;
-  }
-
-  // Check that the SessionManager has not been shutdown before we try and
-  // resolve any promises.
-  if (!mHost) {
-    return;
-  }
-
-  CK_LOGD("ClearKeySessionManager::RemoveSession");
   auto itr = mSessions.find(sessionId);
   if (itr == mSessions.end()) {
     CK_LOGW("ClearKey CDM couldn't remove non-existent session.");
-
-    mHost->OnRejectPromise(aPromiseId,
-                           Error::kInvalidAccessError,
-                           0,
-                           nullptr,
-                           0);
-
+    mCallback->RejectPromise(aPromiseId, kGMPNotFoundError, nullptr, 0);
     return;
   }
 
   ClearKeySession* session = itr->second;
   assert(session);
   string sid = session->Id();
-  bool isPersistent = session->Type() == SessionType::kPersistentLicense;
+  bool isPersistent = session->Type() == kGMPPersistentSession;
   ClearInMemorySessionData(session);
 
   if (!isPersistent) {
-    mHost->OnResolvePromise(aPromiseId);
+    mCallback->ResolvePromise(aPromiseId);
     return;
   }
 
-  mPersistence->PersistentSessionRemoved(sid);
-
-  vector<uint8_t> emptyKeydata;
-
-  function<void()> resolve = [self, aPromiseId, sessionId] ()
-  {
-    if (!self->mHost) {
-      return;
-    }
-    self->mHost->OnResolvePromise(aPromiseId);
-  };
+  ClearKeyPersistence::PersistentSessionRemoved(sid);
 
-  function<void()> reject = [self, aPromiseId, sessionId] ()
-  {
-    if (!self->mHost) {
-      return;
-    }
-    static const char* message = "Could not remove session";
-    self->mHost->OnRejectPromise(aPromiseId,
-                                 Error::kInvalidAccessError,
-                                 0,
-                                 message,
-                                 strlen(message));
-  };
-
-  WriteData(mHost, sessionId, emptyKeydata, move(resolve), move(reject));
+  // Overwrite the record storing the sessionId's key data with a zero
+  // length record to delete it.
+  vector<uint8_t> emptyKeydata;
+  GMPTask* resolve = WrapTask(mCallback, &GMPDecryptorCallback::ResolvePromise, aPromiseId);
+  static const char* message = "Could not remove session";
+  GMPTask* reject = WrapTask(mCallback,
+                             &GMPDecryptorCallback::RejectPromise,
+                             aPromiseId,
+                             kGMPInvalidAccessError,
+                             message,
+                             strlen(message));
+  StoreData(sessionId, emptyKeydata, resolve, reject);
 }
 
 void
 ClearKeySessionManager::SetServerCertificate(uint32_t aPromiseId,
                                              const uint8_t* aServerCert,
                                              uint32_t aServerCertSize)
 {
   // ClearKey CDM doesn't support this method by spec.
   CK_LOGD("ClearKeySessionManager::SetServerCertificate");
-  mHost->OnRejectPromise(aPromiseId,
-                         Error::kNotSupportedError,
-                         0,
-                         nullptr /* message */,
-                         0 /* messageLen */);
+  mCallback->RejectPromise(aPromiseId, kGMPNotSupportedError,
+                           nullptr /* message */, 0 /* messageLen */);
 }
 
-Status
-ClearKeySessionManager::Decrypt(const InputBuffer& aBuffer,
-                                DecryptedBlock* aDecryptedBlock)
+void
+ClearKeySessionManager::Decrypt(GMPBuffer* aBuffer,
+                                GMPEncryptedBufferMetadata* aMetadata)
 {
   CK_LOGD("ClearKeySessionManager::Decrypt");
 
-  CK_LOGARRAY("Key: ", aBuffer.key_id, aBuffer.key_id_size);
+  if (!mThread) {
+    CK_LOGW("No decrypt thread");
+    mCallback->Decrypted(aBuffer, GMPGenericErr);
+    return;
+  }
 
-  Buffer* buffer = mHost->Allocate(aBuffer.data_size);
-  assert(buffer != nullptr);
-  assert(buffer->Data() != nullptr);
-  assert(buffer->Capacity() >= aBuffer.data_size);
-
-  memcpy(buffer->Data(), aBuffer.data, aBuffer.data_size);
+  mThread->Post(WrapTaskRefCounted(this,
+                                   &ClearKeySessionManager::DoDecrypt,
+                                   aBuffer, aMetadata));
+}
 
-  Status status = mDecryptionManager->Decrypt(buffer->Data(),
-                                              buffer->Size(),
-                                              CryptoMetaData(&aBuffer));
+void
+ClearKeySessionManager::DoDecrypt(GMPBuffer* aBuffer,
+                                  GMPEncryptedBufferMetadata* aMetadata)
+{
+  CK_LOGD("ClearKeySessionManager::DoDecrypt");
 
-  aDecryptedBlock->SetDecryptedBuffer(buffer);
-  aDecryptedBlock->SetTimestamp(aBuffer.timestamp);
+  GMPErr rv = mDecryptionManager->Decrypt(aBuffer->Data(), aBuffer->Size(),
+                                          CryptoMetaData(aMetadata));
+  CK_LOGD("DeDecrypt finished with code %x\n", rv);
+  mCallback->Decrypted(aBuffer, rv);
+}
 
-  return status;
+void
+ClearKeySessionManager::Shutdown()
+{
+  CK_LOGD("ClearKeySessionManager::Shutdown %p", this);
+
+  for (auto it = mSessions.begin(); it != mSessions.end(); it++) {
+    delete it->second;
+  }
+  mSessions.clear();
 }
 
 void
 ClearKeySessionManager::DecryptingComplete()
 {
   CK_LOGD("ClearKeySessionManager::DecryptingComplete %p", this);
 
-  for (auto it = mSessions.begin(); it != mSessions.end(); it++) {
-    delete it->second;
-  }
-  mSessions.clear();
+  GMPThread* thread = mThread;
+  thread->Join();
 
+  Shutdown();
   mDecryptionManager = nullptr;
-  mHost = nullptr;
-
   Release();
 }
-
-bool ClearKeySessionManager::MaybeDeferTillInitialized(function<void()> aMaybeDefer)
-{
-  if (mPersistence->IsLoaded()) {
-    return false;
-  }
-
-  mDeferredInitialize.emplace(move(aMaybeDefer));
-  return true;
-}
--- a/media/gmp-clearkey/0.1/ClearKeySessionManager.h
+++ b/media/gmp-clearkey/0.1/ClearKeySessionManager.h
@@ -1,102 +1,100 @@
 /*
-* Copyright 2015, Mozilla Foundation and contributors
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * Copyright 2015, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #ifndef __ClearKeyDecryptor_h__
 #define __ClearKeyDecryptor_h__
 
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
 #include "ClearKeyDecryptionManager.h"
-#include "ClearKeyPersistence.h"
 #include "ClearKeySession.h"
 #include "ClearKeyUtils.h"
-// This include is required in order for content_decryption_module to work
-// on Unix systems.
-#include "stddef.h"
-#include "content_decryption_module.h"
+#include "gmp-api/gmp-decryption.h"
 #include "RefCounted.h"
 
-#include <functional>
-#include <map>
-#include <queue>
-#include <set>
-#include <string>
-
-class ClearKeySessionManager final : public RefCounted
+class ClearKeySessionManager final : public GMPDecryptor
+                                   , public RefCounted
 {
 public:
-  explicit ClearKeySessionManager(cdm::Host_8* aHost);
+  ClearKeySessionManager();
 
-  void Init(bool aDistinctiveIdentifierAllowed,
-            bool aPersistentStateAllowed);
+  virtual void Init(GMPDecryptorCallback* aCallback,
+                    bool aDistinctiveIdentifierAllowed,
+                    bool aPersistentStateAllowed) override;
 
-  void CreateSession(uint32_t aPromiseId,
-                     cdm::InitDataType aInitDataType,
-                     const uint8_t* aInitData,
-                     uint32_t aInitDataSize,
-                     cdm::SessionType aSessionType);
+  virtual void CreateSession(uint32_t aCreateSessionToken,
+                             uint32_t aPromiseId,
+                             const char* aInitDataType,
+                             uint32_t aInitDataTypeSize,
+                             const uint8_t* aInitData,
+                             uint32_t aInitDataSize,
+                             GMPSessionType aSessionType) override;
 
-  void LoadSession(uint32_t aPromiseId,
-                   const char* aSessionId,
-                   uint32_t aSessionIdLength);
+  virtual void LoadSession(uint32_t aPromiseId,
+                           const char* aSessionId,
+                           uint32_t aSessionIdLength) override;
 
-  void UpdateSession(uint32_t aPromiseId,
-                     const char* aSessionId,
-                     uint32_t aSessionIdLength,
-                     const uint8_t* aResponse,
-                     uint32_t aResponseSize);
+  virtual void UpdateSession(uint32_t aPromiseId,
+                             const char* aSessionId,
+                             uint32_t aSessionIdLength,
+                             const uint8_t* aResponse,
+                             uint32_t aResponseSize) override;
 
-  void CloseSession(uint32_t aPromiseId,
-                    const char* aSessionId,
-                    uint32_t aSessionIdLength);
+  virtual void CloseSession(uint32_t aPromiseId,
+                            const char* aSessionId,
+                            uint32_t aSessionIdLength) override;
 
-  void RemoveSession(uint32_t aPromiseId,
-                     const char* aSessionId,
-                     uint32_t aSessionIdLength);
+  virtual void RemoveSession(uint32_t aPromiseId,
+                             const char* aSessionId,
+                             uint32_t aSessionIdLength) override;
 
-  void SetServerCertificate(uint32_t aPromiseId,
-                            const uint8_t* aServerCert,
-                            uint32_t aServerCertSize);
+  virtual void SetServerCertificate(uint32_t aPromiseId,
+                                    const uint8_t* aServerCert,
+                                    uint32_t aServerCertSize) override;
 
-  cdm::Status
-  Decrypt(const cdm::InputBuffer& aBuffer,
-          cdm::DecryptedBlock* aDecryptedBlock);
+  virtual void Decrypt(GMPBuffer* aBuffer,
+                       GMPEncryptedBufferMetadata* aMetadata) override;
 
-  void DecryptingComplete();
+  virtual void DecryptingComplete() override;
 
-  void PersistentSessionDataLoaded(uint32_t aPromiseId,
+  void PersistentSessionDataLoaded(GMPErr aStatus,
+                                   uint32_t aPromiseId,
                                    const std::string& aSessionId,
                                    const uint8_t* aKeyData,
                                    uint32_t aKeyDataSize);
 
 private:
   ~ClearKeySessionManager();
 
+  void DoDecrypt(GMPBuffer* aBuffer, GMPEncryptedBufferMetadata* aMetadata);
+  void Shutdown();
+
   void ClearInMemorySessionData(ClearKeySession* aSession);
-  bool MaybeDeferTillInitialized(std::function<void()> aMaybeDefer);
-  void Serialize(const ClearKeySession* aSession,
-                 std::vector<uint8_t>& aOutKeyData);
+  void Serialize(const ClearKeySession* aSession, std::vector<uint8_t>& aOutKeyData);
 
   RefPtr<ClearKeyDecryptionManager> mDecryptionManager;
-  RefPtr<ClearKeyPersistence> mPersistence;
 
-  cdm::Host_8* mHost = nullptr;
+  GMPDecryptorCallback* mCallback;
+  GMPThread* mThread;
 
   std::set<KeyId> mKeyIds;
   std::map<std::string, ClearKeySession*> mSessions;
-
-  std::queue<std::function<void()>> mDeferredInitialize;
 };
 
 #endif // __ClearKeyDecryptor_h__
--- a/media/gmp-clearkey/0.1/ClearKeyStorage.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeyStorage.cpp
@@ -10,217 +10,185 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "ClearKeyStorage.h"
-
 #include "ClearKeyUtils.h"
 
-// This include is required in order for content_decryption_module to work
-// on Unix systems.
-#include "stddef.h"
-#include "content_decryption_module.h"
+#include "gmp-task-utils.h"
 
 #include <assert.h>
 #include "ArrayUtils.h"
+
 #include <vector>
 
-using namespace cdm;
-using namespace std;
+static GMPErr
+RunOnMainThread(GMPTask* aTask)
+{
+  return GetPlatform()->runonmainthread(aTask);
+}
 
-class WriteRecordClient : public FileIOClient
+GMPErr
+OpenRecord(const char* aName,
+           uint32_t aNameLength,
+           GMPRecord** aOutRecord,
+           GMPRecordClient* aClient)
 {
+  return GetPlatform()->createrecord(aName, aNameLength, aOutRecord, aClient);
+}
+
+class WriteRecordClient : public GMPRecordClient {
 public:
   /*
    * This function will take the memory ownership of the parameters and
    * delete them when done.
    */
-  static void Write(Host_8* aHost,
-                    string& aRecordName,
-                    const vector<uint8_t>& aData,
-                    function<void()>&& aOnSuccess,
-                    function<void()>&& aOnFailure)
-{
-    WriteRecordClient* client = new WriteRecordClient(aData,
-                                                      move(aOnSuccess),
-                                                      move(aOnFailure));
-    client->Do(aRecordName, aHost);
+  static void Write(const std::string& aRecordName,
+                    const std::vector<uint8_t>& aData,
+                    GMPTask* aOnSuccess,
+                    GMPTask* aOnFailure) {
+    (new WriteRecordClient(aData, aOnSuccess, aOnFailure))->Do(aRecordName);
   }
 
-  void OnOpenComplete(Status aStatus) override
-  {
-    // If we hit an error, fail.
-    if (aStatus != Status::kSuccess) {
-      Done(aStatus);
-    } else if (mFileIO) { // Otherwise, write our data to the file.
-      mFileIO->Write(&mData[0], mData.size());
+  virtual void OpenComplete(GMPErr aStatus) override {
+    if (GMP_FAILED(aStatus) ||
+        GMP_FAILED(mRecord->Write(&mData.front(), mData.size()))) {
+      Done(mOnFailure, mOnSuccess);
     }
   }
 
-  void OnReadComplete(Status aStatus,
-                      const uint8_t* aData,
-                      uint32_t aDataSize) override
-  {
-    // This function should never be called, we only ever write data with this
-    // client.
-    assert(false);
+  virtual void ReadComplete(GMPErr aStatus,
+                            const uint8_t* aData,
+                            uint32_t aDataSize) override {
+    assert(false); // Should not reach here.
   }
 
-  void OnWriteComplete(Status aStatus) override
-  {
-    Done(aStatus);
+  virtual void WriteComplete(GMPErr aStatus) override {
+    if (GMP_FAILED(aStatus)) {
+      Done(mOnFailure, mOnSuccess);
+    } else {
+      Done(mOnSuccess, mOnFailure);
+    }
   }
 
 private:
-  explicit WriteRecordClient(const vector<uint8_t>& aData,
-                             function<void()>&& aOnSuccess,
-                             function<void()>&& aOnFailure)
-    : mFileIO(nullptr)
-    , mOnSuccess(move(aOnSuccess))
-    , mOnFailure(move(aOnFailure))
+  WriteRecordClient(const std::vector<uint8_t>& aData,
+                    GMPTask* aOnSuccess,
+                    GMPTask* aOnFailure)
+    : mRecord(nullptr)
+    , mOnSuccess(aOnSuccess)
+    , mOnFailure(aOnFailure)
     , mData(aData) {}
 
-  void Do(const string& aName, Host_8* aHost)
-  {
-    // Initialize the FileIO.
-    mFileIO = aHost->CreateFileIO(this);
-    mFileIO->Open(aName.c_str(), aName.size());
+  void Do(const std::string& aName) {
+    auto err = OpenRecord(aName.c_str(), aName.size(), &mRecord, this);
+    if (GMP_FAILED(err) ||
+        GMP_FAILED(mRecord->Open())) {
+      Done(mOnFailure, mOnSuccess);
+    }
   }
 
-  void Done(cdm::FileIOClient::Status aStatus)
-  {
+  void Done(GMPTask* aToRun, GMPTask* aToDestroy) {
     // Note: Call Close() before running continuation, in case the
     // continuation tries to open the same record; if we call Close()
     // after running the continuation, the Close() call will arrive
     // just after the Open() call succeeds, immediately closing the
     // record we just opened.
-    if (mFileIO) {
-      mFileIO->Close();
+    if (mRecord) {
+      mRecord->Close();
     }
-
-    if (IO_SUCCEEDED(aStatus)) {
-      mOnSuccess();
-    } else {
-      mOnFailure();
-    }
-
+    aToDestroy->Destroy();
+    RunOnMainThread(aToRun);
     delete this;
   }
 
-  FileIO* mFileIO = nullptr;
-
-  function<void()> mOnSuccess;
-  function<void()> mOnFailure;
-
-  const vector<uint8_t> mData;
+  GMPRecord* mRecord;
+  GMPTask* mOnSuccess;
+  GMPTask* mOnFailure;
+  const std::vector<uint8_t> mData;
 };
 
 void
-WriteData(Host_8* aHost,
-          string& aRecordName,
-          const vector<uint8_t>& aData,
-          function<void()>&& aOnSuccess,
-          function<void()>&& aOnFailure)
+StoreData(const std::string& aRecordName,
+          const std::vector<uint8_t>& aData,
+          GMPTask* aOnSuccess,
+          GMPTask* aOnFailure)
 {
-  WriteRecordClient::Write(aHost,
-                           aRecordName,
-                           aData,
-                           move(aOnSuccess),
-                           move(aOnFailure));
+  WriteRecordClient::Write(aRecordName, aData, aOnSuccess, aOnFailure);
 }
 
-class ReadRecordClient : public FileIOClient
-{
+class ReadRecordClient : public GMPRecordClient {
 public:
   /*
    * This function will take the memory ownership of the parameters and
    * delete them when done.
    */
-  static void Read(Host_8* aHost,
-                   string& aRecordName,
-                   function<void(const uint8_t*, uint32_t)>&& aOnSuccess,
-                   function<void()>&& aOnFailure)
-  {
-
-    (new ReadRecordClient(move(aOnSuccess), move(aOnFailure)))->
-      Do(aRecordName, aHost);
+  static void Read(const std::string& aRecordName,
+                   ReadContinuation* aContinuation) {
+    assert(aContinuation);
+    (new ReadRecordClient(aContinuation))->Do(aRecordName);
   }
 
-  void OnOpenComplete(Status aStatus) override
-  {
+  virtual void OpenComplete(GMPErr aStatus) override {
     auto err = aStatus;
-    if (aStatus != Status::kSuccess) {
+    if (GMP_FAILED(err) ||
+        GMP_FAILED(err = mRecord->Read())) {
       Done(err, nullptr, 0);
-    } else {
-      mFileIO->Read();
     }
   }
 
-  void OnReadComplete(Status aStatus,
-                      const uint8_t* aData,
-                      uint32_t aDataSize) override
-  {
+  virtual void ReadComplete(GMPErr aStatus,
+                            const uint8_t* aData,
+                            uint32_t aDataSize) override {
     Done(aStatus, aData, aDataSize);
   }
 
-  void OnWriteComplete(Status aStatus) override
-  {
-    // We should never reach here, this client only ever reads data.
-    assert(false);
+  virtual void WriteComplete(GMPErr aStatus) override {
+    assert(false); // Should not reach here.
   }
 
 private:
-  explicit ReadRecordClient(function<void(const uint8_t*, uint32_t)>&& aOnSuccess,
-                            function<void()>&& aOnFailure)
-    : mFileIO(nullptr)
-    , mOnSuccess(move(aOnSuccess))
-    , mOnFailure(move(aOnFailure))
-  {}
+  explicit ReadRecordClient(ReadContinuation* aContinuation)
+    : mRecord(nullptr)
+    , mContinuation(aContinuation) {}
 
-  void Do(const string& aName, Host_8* aHost)
-  {
-    mFileIO = aHost->CreateFileIO(this);
-    mFileIO->Open(aName.c_str(), aName.size());
+  void Do(const std::string& aName) {
+    auto err = OpenRecord(aName.c_str(), aName.size(), &mRecord, this);
+    if (GMP_FAILED(err) ||
+        GMP_FAILED(err = mRecord->Open())) {
+      Done(err, nullptr, 0);
+    }
   }
 
-  void Done(cdm::FileIOClient::Status aStatus,
-            const uint8_t* aData,
-            uint32_t aDataSize)
-  {
+  void Done(GMPErr err, const uint8_t* aData, uint32_t aDataSize) {
     // Note: Call Close() before running continuation, in case the
     // continuation tries to open the same record; if we call Close()
     // after running the continuation, the Close() call will arrive
     // just after the Open() call succeeds, immediately closing the
     // record we just opened.
-    if (mFileIO) {
-      mFileIO->Close();
+    if (mRecord) {
+      mRecord->Close();
     }
-
-    if (IO_SUCCEEDED(aStatus)) {
-      mOnSuccess(aData, aDataSize);
-    } else {
-      mOnFailure();
-    }
-
+    mContinuation->ReadComplete(err, aData, aDataSize);
+    delete mContinuation;
     delete this;
   }
 
-  FileIO* mFileIO = nullptr;
-
-  function<void(const uint8_t*, uint32_t)> mOnSuccess;
-  function<void()> mOnFailure;
+  GMPRecord* mRecord;
+  ReadContinuation* mContinuation;
 };
 
 void
-ReadData(Host_8* mHost,
-         string& aRecordName,
-         function<void(const uint8_t*, uint32_t)>&& aOnSuccess,
-         function<void()>&& aOnFailure)
+ReadData(const std::string& aRecordName,
+         ReadContinuation* aContinuation)
 {
-  ReadRecordClient::Read(mHost,
-                         aRecordName,
-                         move(aOnSuccess),
-                         move(aOnFailure));
+  ReadRecordClient::Read(aRecordName, aContinuation);
 }
+
+GMPErr
+EnumRecordNames(RecvGMPRecordIteratorPtr aRecvIteratorFunc)
+{
+  return GetPlatform()->getrecordenumerator(aRecvIteratorFunc, nullptr);
+}
--- a/media/gmp-clearkey/0.1/ClearKeyStorage.h
+++ b/media/gmp-clearkey/0.1/ClearKeyStorage.h
@@ -12,32 +12,37 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef __ClearKeyStorage_h__
 #define __ClearKeyStorage_h__
 
-#include <functional>
-#include <stdint.h>
+#include "gmp-api/gmp-errors.h"
+#include "gmp-api/gmp-platform.h"
 #include <string>
 #include <vector>
+#include <stdint.h>
 
-#include "ClearKeySessionManager.h"
+class GMPTask;
 
-#define IO_SUCCEEDED(x) ((x) == cdm::FileIOClient::Status::kSuccess)
-#define IO_FAILED(x) ((x) != cdm::FileIOClient::Status::kSuccess)
+// Responsible for ensuring that both aOnSuccess and aOnFailure are destroyed.
+void StoreData(const std::string& aRecordName,
+               const std::vector<uint8_t>& aData,
+               GMPTask* aOnSuccess,
+               GMPTask* aOnFailure);
 
-// Writes data to a file and fires the appropriate callback when complete.
-void WriteData(cdm::Host_8* aHost,
-               std::string& aRecordName,
-               const std::vector<uint8_t>& aData,
-               std::function<void()>&& aOnSuccess,
-               std::function<void()>&& aOnFailure);
+class ReadContinuation {
+public:
+  virtual void ReadComplete(GMPErr aStatus,
+                            const uint8_t* aData,
+                            uint32_t aLength) = 0;
+  virtual ~ReadContinuation() {}
+};
 
-// Reads data from a file and fires the appropriate callback when complete.
-void ReadData(cdm::Host_8* aHost,
-              std::string& aRecordName,
-              std::function<void(const uint8_t*, uint32_t)>&& aOnSuccess,
-              std::function<void()>&& aOnFailure);
+// Deletes aContinuation after running it to report the result.
+void ReadData(const std::string& aSessionId,
+              ReadContinuation* aContinuation);
+
+GMPErr EnumRecordNames(RecvGMPRecordIteratorPtr aRecvIteratorFunc);
 
 #endif // __ClearKeyStorage_h__
--- a/media/gmp-clearkey/0.1/ClearKeyUtils.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeyUtils.cpp
@@ -9,87 +9,43 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-#include "ClearKeyUtils.h"
-
 #include <algorithm>
-#include <assert.h>
-#include <stdlib.h>
-#include <cctype>
 #include <ctype.h>
-#include <memory.h>
-#include <sstream>
 #include <stdarg.h>
 #include <stdint.h>
-#include <stdio.h>
 #include <vector>
 
-#include "ArrayUtils.h"
-#include "BigEndian.h"
+#include "ClearKeyUtils.h"
 #include "ClearKeyBase64.h"
-// This include is required in order for content_decryption_module to work
-// on Unix systems.
-#include "stddef.h"
-#include "content_decryption_module.h"
+#include "ArrayUtils.h"
+#include <assert.h>
+#include <memory.h>
+#include "BigEndian.h"
 #include "openaes/oaes_lib.h"
-#include "psshparser/PsshParser.h"
 
-using namespace cdm;
 using namespace std;
 
 void
 CK_Log(const char* aFmt, ...)
 {
-  FILE* out = stdout;
-
-  if (getenv("CLEARKEY_LOG_FILE")) {
-    out = fopen(getenv("CLEARKEY_LOG_FILE"), "a");
-  }
-
   va_list ap;
 
   va_start(ap, aFmt);
-  const size_t len = 1024;
-  char buf[len];
-  vsnprintf(buf, len, aFmt, ap);
+  vprintf(aFmt, ap);
   va_end(ap);
 
-  fprintf(out, "%s\n", buf);
-  fflush(out);
-
-  if (out != stdout) {
-    fclose(out);
-  }
-}
-
-static bool
-PrintableAsString(const uint8_t* aBytes, uint32_t aLength)
-{
-  return all_of(aBytes, aBytes + aLength, [] (uint8_t c) {
-    return isprint(c) == 1;
-  });
-}
-
-void
-CK_LogArray(const char* prepend,
-            const uint8_t* aData,
-            const uint32_t aDataSize)
-{
-  // If the data is valid ascii, use that. Otherwise print the hex
-  string data = PrintableAsString(aData, aDataSize) ?
-                string(aData, aData + aDataSize) :
-                ClearKeyUtils::ToHexString(aData, aDataSize);
-
-  CK_LOGD("%s%s", prepend, data.c_str());
+  printf("\n");
+  fflush(stdout);
 }
 
 static void
 IncrementIV(vector<uint8_t>& aIV) {
   using mozilla::BigEndian;
 
   assert(aIV.size() == 16);
   BigEndian::writeUint64(&aIV[8], BigEndian::readUint64(&aIV[8]) + 1);
@@ -154,29 +110,27 @@ EncodeBase64Web(vector<uint8_t> aBinary,
     }
 
     out[i] += (*data >> (shift + 2)) & sMask;
     shift = (shift + 2) % 8;
 
     // Cast idx to size_t before using it as an array-index,
     // to pacify clang 'Wchar-subscripts' warning:
     size_t idx = static_cast<size_t>(out[i]);
-
-    // out of bounds index for 'sAlphabet'
-    assert(idx < MOZ_ARRAY_LENGTH(sAlphabet));
+    assert(idx < MOZ_ARRAY_LENGTH(sAlphabet)); // out of bounds index for 'sAlphabet'
     out[i] = sAlphabet[idx];
   }
 
   return true;
 }
 
 /* static */ void
 ClearKeyUtils::MakeKeyRequest(const vector<KeyId>& aKeyIDs,
                               string& aOutRequest,
-                              SessionType aSessionType)
+                              GMPSessionType aSessionType)
 {
   assert(aKeyIDs.size() && aOutRequest.empty());
 
   aOutRequest.append("{\"kids\":[");
   for (size_t i = 0; i < aKeyIDs.size(); i++) {
     if (i) {
       aOutRequest.append(",");
     }
@@ -430,17 +384,17 @@ ParseKeys(ParserContext& aCtx, vector<Ke
   }
 
   return GetNextSymbol(aCtx) == ']';
 }
 
 /* static */ bool
 ClearKeyUtils::ParseJWK(const uint8_t* aKeyData, uint32_t aKeyDataSize,
                         vector<KeyIdPair>& aOutKeys,
-                        SessionType aSessionType)
+                        GMPSessionType aSessionType)
 {
   ParserContext ctx;
   ctx.mIter = aKeyData;
   ctx.mEnd = aKeyData + aKeyDataSize;
 
   // Consume '{' from start of object.
   EXPECT_SYMBOL(ctx, '{');
 
@@ -546,26 +500,25 @@ ClearKeyUtils::ParseKeyIdsInitData(const
 
   // Consume '}' from end of object.
   EXPECT_SYMBOL(ctx, '}');
 
   return true;
 }
 
 /* static */ const char*
-ClearKeyUtils::SessionTypeToString(SessionType aSessionType)
+ClearKeyUtils::SessionTypeToString(GMPSessionType aSessionType)
 {
   switch (aSessionType) {
-  case SessionType::kTemporary: return "temporary";
-  case SessionType::kPersistentLicense: return "persistent-license";
-  default: {
-    // We don't support any other license types.
-    assert(false);
-    return "invalid";
-  }
+    case kGMPTemporySession: return "temporary";
+    case kGMPPersistentSession: return "persistent-license";
+    default: {
+      assert(false); // Should not reach here.
+      return "invalid";
+    }
   }
 }
 
 /* static */ bool
 ClearKeyUtils::IsValidSessionId(const char* aBuff, uint32_t aLength)
 {
   if (aLength > 10) {
     // 10 is the max number of characters in UINT32_MAX when
@@ -575,20 +528,14 @@ ClearKeyUtils::IsValidSessionId(const ch
   for (uint32_t i = 0; i < aLength; i++) {
     if (!isdigit(aBuff[i])) {
       return false;
     }
   }
   return true;
 }
 
-string
-ClearKeyUtils::ToHexString(const uint8_t * aBytes, uint32_t aLength)
-{
-  stringstream ss;
-  ss << std::showbase << std::uppercase << std::hex;
-  for (uint32_t i = 0; i < aLength; ++i) {
-    ss << std::hex << static_cast<uint32_t>(aBytes[i]);
-    ss << " ";
-  }
-
-  return ss.str();
+GMPMutex* GMPCreateMutex() {
+  GMPMutex* mutex;
+  auto err = GetPlatform()->createmutex(&mutex);
+  assert(mutex);
+  return GMP_FAILED(err) ? nullptr : mutex;
 }
--- a/media/gmp-clearkey/0.1/ClearKeyUtils.h
+++ b/media/gmp-clearkey/0.1/ClearKeyUtils.h
@@ -16,54 +16,43 @@
 
 #ifndef __ClearKeyUtils_h__
 #define __ClearKeyUtils_h__
 
 #include <stdint.h>
 #include <string>
 #include <vector>
 #include <assert.h>
-
-// This include is required in order for content_decryption_module to work
-// on Unix systems.
-#include "stddef.h"
-#include "content_decryption_module.h"
+#include "gmp-api/gmp-decryption.h"
 
 #if 0
 void CK_Log(const char* aFmt, ...);
 #define CK_LOGE(...) CK_Log(__VA_ARGS__)
 #define CK_LOGD(...) CK_Log(__VA_ARGS__)
 #define CK_LOGW(...) CK_Log(__VA_ARGS__)
-#define CK_LOGARRAY(APREPEND, ADATA, ADATA_SIZE) CK_LogArray(APREPEND, \
-  ADATA, \
-  ADATA_SIZE)
 #else
-// Note: Enabling logging slows things down a LOT, especially when logging to
-// a file.
 #define CK_LOGE(...)
 #define CK_LOGD(...)
 #define CK_LOGW(...)
-#define CK_LOGARRAY(APREPEND, ADATA, ADATA_SIZE)
 #endif
 
+struct GMPPlatformAPI;
+extern GMPPlatformAPI* GetPlatform();
+
 typedef std::vector<uint8_t> KeyId;
 typedef std::vector<uint8_t> Key;
 
 // The session response size should be within a reasonable limit.
 // The size 64 KB is referenced from web-platform-test.
 static const uint32_t kMaxSessionResponseLength = 65536;
 
 // Provide limitation for KeyIds length and webm initData size.
 static const uint32_t kMaxWebmInitDataSize = 65536;
 static const uint32_t kMaxKeyIdsLength = 512;
 
-void CK_LogArray(const char* aPrepend,
-                 const uint8_t* aData,
-                 const uint32_t aDataSize);
-
 struct KeyIdPair
 {
   KeyId mKeyId;
   Key mKey;
 };
 
 class ClearKeyUtils
 {
@@ -72,35 +61,54 @@ public:
                          std::vector<uint8_t>& aData, std::vector<uint8_t>& aIV);
 
   static bool ParseKeyIdsInitData(const uint8_t* aInitData,
                                   uint32_t aInitDataSize,
                                   std::vector<KeyId>& aOutKeyIds);
 
   static void MakeKeyRequest(const std::vector<KeyId>& aKeyIds,
                              std::string& aOutRequest,
-                             cdm::SessionType aSessionType);
+                             GMPSessionType aSessionType);
 
   static bool ParseJWK(const uint8_t* aKeyData, uint32_t aKeyDataSize,
                        std::vector<KeyIdPair>& aOutKeys,
-                       cdm::SessionType aSessionType);
-  static const char* SessionTypeToString(cdm::SessionType aSessionType);
+                       GMPSessionType aSessionType);
+  static const char* SessionTypeToString(GMPSessionType aSessionType);
 
   static bool IsValidSessionId(const char* aBuff, uint32_t aLength);
-
-  static std::string ToHexString(const uint8_t * aBytes, uint32_t aLength);
 };
 
 template<class Container, class Element>
 inline bool
 Contains(const Container& aContainer, const Element& aElement)
 {
   return aContainer.find(aElement) != aContainer.end();
 }
 
+class AutoLock {
+public:
+  explicit AutoLock(GMPMutex* aMutex)
+    : mMutex(aMutex)
+  {
+    assert(aMutex);
+    if (mMutex) {
+      mMutex->Acquire();
+    }
+  }
+  ~AutoLock() {
+    if (mMutex) {
+      mMutex->Release();
+    }
+  }
+private:
+  GMPMutex* mMutex;
+};
+
+GMPMutex* GMPCreateMutex();
+
 template<typename T>
 inline void
 Assign(std::vector<T>& aVec, const T* aData, size_t aLength)
 {
   aVec.assign(aData, aData + aLength);
 }
 
 #endif // __ClearKeyUtils_h__
--- a/media/gmp-clearkey/0.1/RefCounted.h
+++ b/media/gmp-clearkey/0.1/RefCounted.h
@@ -16,17 +16,51 @@
 
 #ifndef __RefCount_h__
 #define __RefCount_h__
 
 #include <stdint.h>
 #include <assert.h>
 #include "ClearKeyUtils.h"
 
+#if defined(_MSC_VER)
 #include <atomic>
+typedef std::atomic<uint32_t> AtomicRefCount;
+#else
+class AtomicRefCount {
+public:
+  explicit AtomicRefCount(uint32_t aValue)
+    : mCount(aValue)
+    , mMutex(GMPCreateMutex())
+  {
+    assert(mMutex);
+  }
+  ~AtomicRefCount()
+  {
+    if (mMutex) {
+      mMutex->Destroy();
+    }
+  }
+  uint32_t operator--() {
+    AutoLock lock(mMutex);
+    return --mCount;
+  }
+  uint32_t operator++() {
+    AutoLock lock(mMutex);
+    return ++mCount;
+  }
+  operator uint32_t() {
+    AutoLock lock(mMutex);
+    return mCount;
+  }
+private:
+  uint32_t mCount;
+  GMPMutex* mMutex;
+};
+#endif
 
 // Note: Thread safe.
 class RefCounted {
 public:
   void AddRef() {
     ++mRefCount;
   }
 
@@ -42,57 +76,41 @@ protected:
   RefCounted()
     : mRefCount(0)
   {
   }
   virtual ~RefCounted()
   {
     assert(!mRefCount);
   }
-  std::atomic<uint32_t> mRefCount;
+  AtomicRefCount mRefCount;
 };
 
 template<class T>
 class RefPtr {
 public:
-  RefPtr(const RefPtr& src) {
-    Set(src.mPtr);
+  explicit RefPtr(T* aPtr) : mPtr(nullptr) {
+    Assign(aPtr);
   }
-
-  explicit RefPtr(T* aPtr) {
-    Set(aPtr);
-  }
-  RefPtr() { Set(nullptr); }
-
   ~RefPtr() {
-    Set(nullptr);
+    Assign(nullptr);
   }
   T* operator->() const { return mPtr; }
-  T** operator&() { return &mPtr; }
-  T* operator->() { return mPtr; }
-  operator T*() { return mPtr; }
-
-  T* Get() const { return mPtr; }
 
   RefPtr& operator=(T* aVal) {
-    Set(aVal);
+    Assign(aVal);
     return *this;
   }
 
 private:
-  T* Set(T* aPtr) {
-    if (mPtr == aPtr) {
-      return aPtr;
-    }
+  void Assign(T* aPtr) {
     if (mPtr) {
       mPtr->Release();
     }
     mPtr = aPtr;
     if (mPtr) {
       aPtr->AddRef();
     }
-    return mPtr;
   }
-
-  T* mPtr = nullptr;
+  T* mPtr;
 };
 
 #endif // __RefCount_h__
--- a/media/gmp-clearkey/0.1/VideoDecoder.cpp
+++ b/media/gmp-clearkey/0.1/VideoDecoder.cpp
@@ -9,310 +9,447 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-#include <algorithm>
 #include <cstdint>
 #include <limits>
 
+#include "AnnexB.h"
 #include "BigEndian.h"
 #include "ClearKeyDecryptionManager.h"
 #include "ClearKeyUtils.h"
+#include "gmp-task-utils.h"
 #include "VideoDecoder.h"
 
 using namespace wmf;
-using namespace cdm;
 
-VideoDecoder::VideoDecoder(Host_8 *aHost)
-  : mHost(aHost)
+VideoDecoder::VideoDecoder(GMPVideoHost *aHostAPI)
+  : mHostAPI(aHostAPI)
+  , mCallback(nullptr)
+  , mWorkerThread(nullptr)
+  , mMutex(nullptr)
+  , mNumInputTasks(0)
+  , mSentExtraData(false)
+  , mIsFlushing(false)
   , mHasShutdown(false)
 {
   // We drop the ref in DecodingComplete().
   AddRef();
-
-  mDecoder = new WMFH264Decoder();
-
-  uint32_t cores = std::max(1u, std::thread::hardware_concurrency());
-  HRESULT hr = mDecoder->Init(cores);
 }
 
 VideoDecoder::~VideoDecoder()
 {
-
+  if (mMutex) {
+    mMutex->Destroy();
+  }
 }
 
-Status
-VideoDecoder::InitDecode(const VideoDecoderConfig& aConfig)
+void
+VideoDecoder::InitDecode(const GMPVideoCodec& aCodecSettings,
+                         const uint8_t* aCodecSpecific,
+                         uint32_t aCodecSpecificLength,
+                         GMPVideoDecoderCallback* aCallback,
+                         int32_t aCoreCount)
 {
-  if (!mDecoder) {
+  mCallback = aCallback;
+  assert(mCallback);
+  mDecoder = new WMFH264Decoder();
+  HRESULT hr = mDecoder->Init(aCoreCount);
+  if (FAILED(hr)) {
     CK_LOGD("VideoDecoder::InitDecode failed to init WMFH264Decoder");
+    mCallback->Error(GMPGenericErr);
+    return;
+  }
 
-    return Status::kDecodeError;
+  auto err = GetPlatform()->createmutex(&mMutex);
+  if (GMP_FAILED(err)) {
+    CK_LOGD("VideoDecoder::InitDecode failed to create GMPMutex");
+    mCallback->Error(GMPGenericErr);
+    return;
   }
 
-  return Status::kSuccess;
+  // The first byte is mPacketizationMode, which is only relevant for
+  // WebRTC/OpenH264 usecase.
+  const uint8_t* avcc = aCodecSpecific + 1;
+  const uint8_t* avccEnd = aCodecSpecific + aCodecSpecificLength;
+  mExtraData.insert(mExtraData.end(), avcc, avccEnd);
+
+  AnnexB::ConvertConfig(mExtraData, mAnnexB);
 }
 
-Status
-VideoDecoder::Decode(const InputBuffer& aInputBuffer, VideoFrame* aVideoFrame)
+void
+VideoDecoder::EnsureWorker()
 {
-  // If the input buffer we have been passed has a null buffer, it means we
-  // should drain.
-  if (!aInputBuffer.data) {
-    // This will drain the decoder until there are no frames left to drain,
-    // whereupon it will return 'NeedsMoreData'.
-    CK_LOGD("Input buffer null: Draining");
-    return Drain(aVideoFrame);
+  if (!mWorkerThread) {
+    GetPlatform()->createthread(&mWorkerThread);
+    if (!mWorkerThread) {
+      mCallback->Error(GMPAllocErr);
+      return;
+    }
+  }
+}
+
+void
+VideoDecoder::Decode(GMPVideoEncodedFrame* aInputFrame,
+                     bool aMissingFrames,
+                     const uint8_t* aCodecSpecificInfo,
+                     uint32_t aCodecSpecificInfoLength,
+                     int64_t aRenderTimeMs)
+{
+  if (aInputFrame->BufferType() != GMP_BufferLength32) {
+    // Gecko should only send frames with 4 byte NAL sizes to GMPs.
+    mCallback->Error(GMPGenericErr);
+    return;
   }
 
+  EnsureWorker();
+
+  {
+    AutoLock lock(mMutex);
+    mNumInputTasks++;
+  }
+
+  // Note: we don't need the codec specific info on a per-frame basis.
+  // It's mostly useful for WebRTC use cases.
+
+  // Make a copy of the data, so we can release aInputFrame ASAP,
+  // to avoid too many shmem handles being held by the GMP process.
+  // If the GMP process holds on to too many shmem handles, the Gecko
+  // side can fail to allocate a shmem to send more input. This is
+  // particularly a problem in Gecko mochitests, which can open multiple
+  // actors at once which share the same pool of shmems.
   DecodeData* data = new DecodeData();
-  Assign(data->mBuffer, aInputBuffer.data, aInputBuffer.data_size);
-  data->mTimestamp = aInputBuffer.timestamp;
-  data->mCrypto = CryptoMetaData(&aInputBuffer);
+  Assign(data->mBuffer, aInputFrame->Buffer(), aInputFrame->Size());
+  data->mTimestamp = aInputFrame->TimeStamp();
+  data->mDuration = aInputFrame->Duration();
+  data->mIsKeyframe = (aInputFrame->FrameType() == kGMPKeyFrame);
+  const GMPEncryptedBufferMetadata* crypto = aInputFrame->GetDecryptionData();
+  if (crypto) {
+    data->mCrypto.Init(crypto);
+  }
+  aInputFrame->Destroy();
+  mWorkerThread->Post(WrapTaskRefCounted(this,
+                                         &VideoDecoder::DecodeTask,
+                                         data));
+}
 
+void
+VideoDecoder::DecodeTask(DecodeData* aData)
+{
   CK_LOGD("VideoDecoder::DecodeTask");
-  AutoPtr<DecodeData> d(data);
+  AutoPtr<DecodeData> d(aData);
   HRESULT hr;
 
-  if (!data || !mDecoder) {
+  {
+    AutoLock lock(mMutex);
+    mNumInputTasks--;
+    assert(mNumInputTasks >= 0);
+  }
+
+  if (mIsFlushing) {
+    CK_LOGD("VideoDecoder::DecodeTask rejecting frame: flushing.");
+    return;
+  }
+
+  if (!aData || !mHostAPI || !mDecoder) {
     CK_LOGE("Decode job not set up correctly!");
-    return Status::kDecodeError;
+    return;
   }
 
-  std::vector<uint8_t>& buffer = data->mBuffer;
-
-  if (data->mCrypto.IsValid()) {
-    Status rv =
-      ClearKeyDecryptionManager::Get()->Decrypt(buffer, data->mCrypto);
+  std::vector<uint8_t>& buffer = aData->mBuffer;
+  if (aData->mCrypto.IsValid()) {
+    // Plugin host should have set up its decryptor/key sessions
+    // before trying to decode!
+    GMPErr rv =
+      ClearKeyDecryptionManager::Get()->Decrypt(buffer, aData->mCrypto);
 
-    if (STATUS_FAILED(rv)) {
-      CK_LOGARRAY("Failed to decrypt video using key ",
-                  aInputBuffer.key_id,
-                  aInputBuffer.key_id_size);
-      return rv;
+    if (GMP_FAILED(rv)) {
+      MaybeRunOnMainThread(WrapTask(mCallback, &GMPVideoDecoderCallback::Error, rv));
+      return;
     }
   }
 
+  AnnexB::ConvertFrameInPlace(buffer);
+
+  if (aData->mIsKeyframe) {
+    // We must send the SPS and PPS to Windows Media Foundation's decoder.
+    // Note: We do this *after* decryption, otherwise the subsample info
+    // would be incorrect.
+    buffer.insert(buffer.begin(), mAnnexB.begin(), mAnnexB.end());
+  }
+
   hr = mDecoder->Input(buffer.data(),
                        buffer.size(),
-                       data->mTimestamp);
+                       aData->mTimestamp,
+                       aData->mDuration);
 
   CK_LOGD("VideoDecoder::DecodeTask() Input ret hr=0x%x\n", hr);
-
-
   if (FAILED(hr)) {
-    assert(hr != MF_E_TRANSFORM_NEED_MORE_INPUT);
-
     CK_LOGE("VideoDecoder::DecodeTask() decode failed ret=0x%x%s\n",
-      hr,
-      ((hr == MF_E_NOTACCEPTING) ? " (MF_E_NOTACCEPTING)" : ""));
-    CK_LOGD("Decode failed. The decoder is not accepting input");
-    return Status::kDecodeError;
+        hr,
+        ((hr == MF_E_NOTACCEPTING) ? " (MF_E_NOTACCEPTING)" : ""));
+    return;
   }
 
-  return OutputFrame(aVideoFrame);
-}
-
-Status VideoDecoder::OutputFrame(VideoFrame* aVideoFrame) {
-  HRESULT hr = S_OK;
-
-  // Read all the output from the decoder. Ideally, this would be a while loop
-  // where we read the output and check the result as the condition. However,
-  // this produces a memory leak connected to assigning a new CComPtr to the
-  // address of the old one, which avoids the CComPtr cleaning up.
-  while (true) {
+  while (hr == S_OK) {
     CComPtr<IMFSample> output;
     hr = mDecoder->Output(&output);
-
-    if (hr != S_OK) {
-      break;
+    CK_LOGD("VideoDecoder::DecodeTask() output ret=0x%x\n", hr);
+    if (hr == S_OK) {
+      MaybeRunOnMainThread(
+        WrapTaskRefCounted(this,
+                           &VideoDecoder::ReturnOutput,
+                           CComPtr<IMFSample>(output),
+                           mDecoder->GetFrameWidth(),
+                           mDecoder->GetFrameHeight(),
+                           mDecoder->GetStride()));
     }
-
-    CK_LOGD("VideoDecoder::DecodeTask() output ret=0x%x\n", hr);
+    if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
+      AutoLock lock(mMutex);
+      if (mNumInputTasks == 0) {
+        // We have run all input tasks. We *must* notify Gecko so that it will
+        // send us more data.
+        MaybeRunOnMainThread(
+          WrapTask(mCallback,
+                   &GMPVideoDecoderCallback::InputDataExhausted));
+      }
+    }
+    if (FAILED(hr)) {
+      CK_LOGE("VideoDecoder::DecodeTask() output failed hr=0x%x\n", hr);
+    }
+  }
+}
 
-    mOutputQueue.push(output);
-    CK_LOGD("Queue size: %u", mOutputQueue.size());
-  }
+void
+VideoDecoder::ReturnOutput(IMFSample* aSample,
+                           int32_t aWidth,
+                           int32_t aHeight,
+                           int32_t aStride)
+{
+  CK_LOGD("[%p] VideoDecoder::ReturnOutput()\n", this);
+  assert(aSample);
+
+  HRESULT hr;
 
-  // If we don't have any inputs, we need more data.
-  if (mOutputQueue.empty()) {
-    CK_LOGD("Decode failed. Not enought data; Requesting more input");
-    return Status::kNeedMoreData;
+  GMPVideoFrame* f = nullptr;
+  auto err = mHostAPI->CreateFrame(kGMPI420VideoFrame, &f);
+  if (GMP_FAILED(err) || !f) {
+    CK_LOGE("Failed to create i420 frame!\n");
+    return;
+  }
+  if (HasShutdown()) {
+    // Note: GMPVideoHost::CreateFrame() can process messages before returning,
+    // including a message that calls VideoDecoder::DecodingComplete(), i.e.
+    // we can shutdown during the call!
+    CK_LOGD("Shutdown while waiting on GMPVideoHost::CreateFrame()!\n");
+    f->Destroy();
+    return;
   }
 
-  // We will get a MF_E_TRANSFORM_NEED_MORE_INPUT every time, as we always
-  // consume everything in the buffer.
-  if (hr != MF_E_TRANSFORM_NEED_MORE_INPUT && FAILED(hr)) {
-    CK_LOGD("Decode failed output ret=0x%x\n", hr);
-    return Status::kDecodeError;
-  }
-
-  CComPtr<IMFSample> result = mOutputQueue.front();
-  mOutputQueue.pop();
+  auto vf = static_cast<GMPVideoi420Frame*>(f);
 
-  // The Chromium CDM API doesn't have support for negative strides, though
-  // they are theoretically possible in real world data.
-  if (mDecoder->GetStride() <= 0) {
-    return Status::kDecodeError;
-  }
+  hr = SampleToVideoFrame(aSample, aWidth, aHeight, aStride, vf);
+  ENSURE(SUCCEEDED(hr), /*void*/);
 
-  hr = SampleToVideoFrame(result,
-                          mDecoder->GetFrameWidth(),
-                          mDecoder->GetFrameHeight(),
-                          mDecoder->GetStride(),
-                          aVideoFrame);
-  if (FAILED(hr)) {
-    return Status::kDecodeError;
-  }
-
-  CK_LOGD("Decode succeeded.");
-  return Status::kSuccess;
+  mCallback->Decoded(vf);
 }
 
 HRESULT
 VideoDecoder::SampleToVideoFrame(IMFSample* aSample,
                                  int32_t aWidth,
                                  int32_t aHeight,
                                  int32_t aStride,
-                                 VideoFrame* aVideoFrame)
+                                 GMPVideoi420Frame* aVideoFrame)
 {
-  CK_LOGD("[%p] VideoDecoder::SampleToVideoFrame()\n", this);
-  assert(aSample);
-
   ENSURE(aSample != nullptr, E_POINTER);
   ENSURE(aVideoFrame != nullptr, E_POINTER);
 
   HRESULT hr;
   CComPtr<IMFMediaBuffer> mediaBuffer;
 
-  aVideoFrame->SetFormat(kI420);
-
   // Must convert to contiguous mediaBuffer to use IMD2DBuffer interface.
   hr = aSample->ConvertToContiguousBuffer(&mediaBuffer);
   ENSURE(SUCCEEDED(hr), hr);
 
   // Try and use the IMF2DBuffer interface if available, otherwise fallback
   // to the IMFMediaBuffer interface. Apparently IMF2DBuffer is more efficient,
   // but only some systems (Windows 8?) support it.
   BYTE* data = nullptr;
   LONG stride = 0;
   CComPtr<IMF2DBuffer> twoDBuffer;
   hr = mediaBuffer->QueryInterface(static_cast<IMF2DBuffer**>(&twoDBuffer));
   if (SUCCEEDED(hr)) {
     hr = twoDBuffer->Lock2D(&data, &stride);
     ENSURE(SUCCEEDED(hr), hr);
   } else {
-    hr = mediaBuffer->Lock(&data, nullptr, nullptr);
+    hr = mediaBuffer->Lock(&data, NULL, NULL);
     ENSURE(SUCCEEDED(hr), hr);
     stride = aStride;
   }
 
-  // The U and V planes are stored 16-row-aligned, so we need to add padding
+  // The V and U planes are stored 16-row-aligned, so we need to add padding
   // to the row heights to ensure the Y'CbCr planes are referenced properly.
-  // YV12, planar format: [YYYY....][UUUU....][VVVV....]
-  // i.e., Y, then U, then V.
+  // YV12, planar format: [YYYY....][VVVV....][UUUU....]
+  // i.e., Y, then V, then U.
   uint32_t padding = 0;
   if (aHeight % 16 != 0) {
     padding = 16 - (aHeight % 16);
   }
-  uint32_t ySize = stride * (aHeight + padding);
-  uint32_t uSize = stride * (aHeight + padding) / 4;
-  uint32_t halfStride = (stride + 1) / 2;
-  uint32_t halfHeight = (aHeight + 1) / 2;
-
-  aVideoFrame->SetStride(VideoFrame::kYPlane, stride);
-  aVideoFrame->SetStride(VideoFrame::kUPlane, halfStride);
-  aVideoFrame->SetStride(VideoFrame::kVPlane, halfStride);
+  int32_t y_size = stride * (aHeight + padding);
+  int32_t v_size = stride * (aHeight + padding) / 4;
+  int32_t halfStride = (stride + 1) / 2;
+  int32_t halfHeight = (aHeight + 1) / 2;
 
-  aVideoFrame->SetSize(Size(aWidth, aHeight));
-
-  uint64_t bufferSize = ySize + 2 * uSize;
+  auto err = aVideoFrame->CreateEmptyFrame(stride, aHeight, stride, halfStride, halfStride);
+  ENSURE(GMP_SUCCEEDED(err), E_FAIL);
 
-  // If the buffer is bigger than the max for a 32 bit, fail to avoid buffer
-  // overflows.
-  if (bufferSize > UINT32_MAX) {
-    return Status::kDecodeError;
-  }
+  err = aVideoFrame->SetWidth(aWidth);
+  ENSURE(GMP_SUCCEEDED(err), E_FAIL);
+  err = aVideoFrame->SetHeight(aHeight);
+  ENSURE(GMP_SUCCEEDED(err), E_FAIL);
 
-  // Get the buffer from the host.
-  Buffer* buffer = mHost->Allocate(bufferSize);
-  aVideoFrame->SetFrameBuffer(buffer);
-
-  // Make sure the buffer is non-null (allocate guarantees it will be of
-  // sufficient size).
-  if (!buffer) {
-    return E_OUTOFMEMORY;
-  }
+  uint8_t* outBuffer = aVideoFrame->Buffer(kGMPYPlane);
+  ENSURE(outBuffer != nullptr, E_FAIL);
+  assert(aVideoFrame->AllocatedSize(kGMPYPlane) >= stride*aHeight);
+  memcpy(outBuffer, data, stride*aHeight);
 
-  uint8_t* outBuffer = buffer->Data();
-
-  aVideoFrame->SetPlaneOffset(VideoFrame::kYPlane, 0);
+  outBuffer = aVideoFrame->Buffer(kGMPUPlane);
+  ENSURE(outBuffer != nullptr, E_FAIL);
+  assert(aVideoFrame->AllocatedSize(kGMPUPlane) >= halfStride*halfHeight);
+  memcpy(outBuffer, data+y_size, halfStride*halfHeight);
 
-  // Offset is the size of the copied y data.
-  aVideoFrame->SetPlaneOffset(VideoFrame::kUPlane, ySize);
-
-  // Offset is the size of the copied y data + the size of the copied u data.
-  aVideoFrame->SetPlaneOffset(VideoFrame::kVPlane, ySize + uSize);
-
-  // Copy the data.
-  memcpy(outBuffer, data, ySize + uSize * 2);
+  outBuffer = aVideoFrame->Buffer(kGMPVPlane);
+  ENSURE(outBuffer != nullptr, E_FAIL);
+  assert(aVideoFrame->AllocatedSize(kGMPVPlane) >= halfStride*halfHeight);
+  memcpy(outBuffer, data + y_size + v_size, halfStride*halfHeight);
 
   if (twoDBuffer) {
     twoDBuffer->Unlock2D();
   } else {
     mediaBuffer->Unlock();
   }
 
   LONGLONG hns = 0;
   hr = aSample->GetSampleTime(&hns);
   ENSURE(SUCCEEDED(hr), hr);
-
   aVideoFrame->SetTimestamp(HNsToUsecs(hns));
 
+  hr = aSample->GetSampleDuration(&hns);
+  ENSURE(SUCCEEDED(hr), hr);
+  aVideoFrame->SetDuration(HNsToUsecs(hns));
+
   return S_OK;
 }
 
 void
+VideoDecoder::ResetCompleteTask()
+{
+  mIsFlushing = false;
+  if (mCallback) {
+    MaybeRunOnMainThread(WrapTask(mCallback,
+                                  &GMPVideoDecoderCallback::ResetComplete));
+  }
+}
+
+void
 VideoDecoder::Reset()
 {
-  CK_LOGD("VideoDecoder::Reset");
-
+  mIsFlushing = true;
   if (mDecoder) {
     mDecoder->Reset();
   }
 
-  // Remove all the frames from the output queue.
-  while (!mOutputQueue.empty()) {
-    mOutputQueue.pop();
-  }
+  // Schedule ResetComplete callback to run after existing frames have been
+  // flushed out of the task queue.
+  EnsureWorker();
+  mWorkerThread->Post(WrapTaskRefCounted(this,
+                                         &VideoDecoder::ResetCompleteTask));
 }
 
-Status
-VideoDecoder::Drain(VideoFrame* aVideoFrame)
+void
+VideoDecoder::DrainTask()
 {
-  CK_LOGD("VideoDecoder::Drain()");
-
-  if (!mDecoder) {
-    CK_LOGD("Drain failed! Decoder was not initialized");
-    return Status::kDecodeError;
-  }
-
   mDecoder->Drain();
 
   // Return any pending output.
-  return OutputFrame(aVideoFrame);
+  HRESULT hr = S_OK;
+  while (hr == S_OK) {
+    CComPtr<IMFSample> output;
+    hr = mDecoder->Output(&output);
+    CK_LOGD("VideoDecoder::DrainTask() output ret=0x%x\n", hr);
+    if (hr == S_OK) {
+      MaybeRunOnMainThread(
+        WrapTaskRefCounted(this,
+                           &VideoDecoder::ReturnOutput,
+                           CComPtr<IMFSample>(output),
+                           mDecoder->GetFrameWidth(),
+                           mDecoder->GetFrameHeight(),
+                           mDecoder->GetStride()));
+    }
+  }
+  MaybeRunOnMainThread(WrapTask(mCallback, &GMPVideoDecoderCallback::DrainComplete));
+}
+
+void
+VideoDecoder::Drain()
+{
+  if (!mDecoder) {
+    if (mCallback) {
+      mCallback->DrainComplete();
+    }
+    return;
+  }
+  EnsureWorker();
+  mWorkerThread->Post(WrapTaskRefCounted(this,
+                                         &VideoDecoder::DrainTask));
 }
 
 void
 VideoDecoder::DecodingComplete()
 {
+  if (mWorkerThread) {
+    mWorkerThread->Join();
+  }
   mHasShutdown = true;
 
   // Release the reference we added in the constructor. There may be
   // WrapRefCounted tasks that also hold references to us, and keep
   // us alive a little longer.
   Release();
 }
+
+void
+VideoDecoder::MaybeRunOnMainThread(GMPTask* aTask)
+{
+  class MaybeRunTask : public GMPTask
+  {
+  public:
+    MaybeRunTask(VideoDecoder* aDecoder, GMPTask* aTask)
+      : mDecoder(aDecoder), mTask(aTask)
+    { }
+
+    virtual void Run(void) {
+      if (mDecoder->HasShutdown()) {
+        CK_LOGD("Trying to dispatch to main thread after VideoDecoder has shut down");
+        return;
+      }
+
+      mTask->Run();
+    }
+
+    virtual void Destroy()
+    {
+      mTask->Destroy();
+      delete this;
+    }
+
+  private:
+    RefPtr<VideoDecoder> mDecoder;
+    GMPTask* mTask;
+  };
+
+  GetPlatform()->runonmainthread(new MaybeRunTask(this, aTask));
+}
--- a/media/gmp-clearkey/0.1/VideoDecoder.h
+++ b/media/gmp-clearkey/0.1/VideoDecoder.h
@@ -13,62 +13,98 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef __VideoDecoder_h__
 #define __VideoDecoder_h__
 
 #include <atomic>
-#include <queue>
-#include <thread>
 
-// This include is required in order for content_decryption_module to work
-// on Unix systems.
-#include "stddef.h"
-#include "content_decryption_module.h"
+#include "gmp-task-utils.h"
+#include "gmp-video-decode.h"
+#include "gmp-video-host.h"
 #include "WMFH264Decoder.h"
 
-class VideoDecoder : public RefCounted
+#include "mfobjects.h"
+
+class VideoDecoder : public GMPVideoDecoder
+                   , public RefCounted
 {
 public:
-  explicit VideoDecoder(cdm::Host_8 *aHost);
+  explicit VideoDecoder(GMPVideoHost *aHostAPI);
 
-  cdm::Status InitDecode(const cdm::VideoDecoderConfig& aConfig);
+  virtual void InitDecode(const GMPVideoCodec& aCodecSettings,
+                          const uint8_t* aCodecSpecific,
+                          uint32_t aCodecSpecificLength,
+                          GMPVideoDecoderCallback* aCallback,
+                          int32_t aCoreCount) override;
 
-  cdm::Status Decode(const cdm::InputBuffer& aEncryptedBuffer,
-                     cdm::VideoFrame* aVideoFrame);
+  virtual void Decode(GMPVideoEncodedFrame* aInputFrame,
+                      bool aMissingFrames,
+                      const uint8_t* aCodecSpecific,
+                      uint32_t aCodecSpecificLength,
+                      int64_t aRenderTimeMs = -1);
 
-  void Reset();
+  virtual void Reset() override;
 
-  void DecodingComplete();
+  virtual void Drain() override;
+
+  virtual void DecodingComplete() override;
 
   bool HasShutdown() { return mHasShutdown; }
 
 private:
 
   virtual ~VideoDecoder();
 
-  cdm::Status Drain(cdm::VideoFrame* aVideoFrame);
+  void EnsureWorker();
+
+  void DrainTask();
 
   struct DecodeData {
+    DecodeData()
+      : mTimestamp(0)
+      , mDuration(0)
+      , mIsKeyframe(false)
+    {}
     std::vector<uint8_t> mBuffer;
-    uint64_t mTimestamp = 0;
+    uint64_t mTimestamp;
+    uint64_t mDuration;
+    bool mIsKeyframe;
     CryptoMetaData mCrypto;
   };
 
-  cdm::Status OutputFrame(cdm::VideoFrame* aVideoFrame);
+  void DecodeTask(DecodeData* aData);
+
+  void ResetCompleteTask();
+
+  void ReturnOutput(IMFSample* aSample,
+                    int32_t aWidth,
+                    int32_t aHeight,
+                    int32_t aStride);
 
   HRESULT SampleToVideoFrame(IMFSample* aSample,
                              int32_t aWidth,
                              int32_t aHeight,
                              int32_t aStride,
-                             cdm::VideoFrame* aVideoFrame);
+                             GMPVideoi420Frame* aVideoFrame);
+
+  void MaybeRunOnMainThread(GMPTask* aTask);
 
-  cdm::Host_8* mHost;
+  GMPVideoHost *mHostAPI; // host-owned, invalid at DecodingComplete
+  GMPVideoDecoderCallback* mCallback; // host-owned, invalid at DecodingComplete
+  GMPThread* mWorkerThread;
+  GMPMutex* mMutex;
   wmf::AutoPtr<wmf::WMFH264Decoder> mDecoder;
 
-  std::queue<wmf::CComPtr<IMFSample>> mOutputQueue;
+  std::vector<uint8_t> mExtraData;
+  std::vector<uint8_t> mAnnexB;
+
+  int32_t mNumInputTasks;
+  bool mSentExtraData;
+
+  std::atomic<bool> mIsFlushing;
 
   bool mHasShutdown;
 };
 
 #endif // __VideoDecoder_h__
--- a/media/gmp-clearkey/0.1/WMFH264Decoder.cpp
+++ b/media/gmp-clearkey/0.1/WMFH264Decoder.cpp
@@ -191,16 +191,17 @@ WMFH264Decoder::SendMFTMessage(MFT_MESSA
   ENSURE(SUCCEEDED(hr), hr);
   return S_OK;
 }
 
 HRESULT
 WMFH264Decoder::CreateInputSample(const uint8_t* aData,
                                   uint32_t aDataSize,
                                   Microseconds aTimestamp,
+                                  Microseconds aDuration,
                                   IMFSample** aOutSample)
 {
   HRESULT hr;
   CComPtr<IMFSample> sample;
   hr = MFCreateSample(&sample);
   ENSURE(SUCCEEDED(hr), hr);
 
   CComPtr<IMFMediaBuffer> buffer;
@@ -225,16 +226,18 @@ WMFH264Decoder::CreateInputSample(const 
   ENSURE(SUCCEEDED(hr), hr);
 
   hr = sample->AddBuffer(buffer);
   ENSURE(SUCCEEDED(hr), hr);
 
   hr = sample->SetSampleTime(UsecsToHNs(aTimestamp));
   ENSURE(SUCCEEDED(hr), hr);
 
+  sample->SetSampleDuration(UsecsToHNs(aDuration));
+
   *aOutSample = sample.Detach();
 
   return S_OK;
 }
 
 HRESULT
 WMFH264Decoder::CreateOutputSample(IMFSample** aOutSample)
 {
@@ -293,21 +296,22 @@ WMFH264Decoder::GetOutputSample(IMFSampl
   // output.pSample
   *aOutSample = sample.Detach(); // AddRefs
   return S_OK;
 }
 
 HRESULT
 WMFH264Decoder::Input(const uint8_t* aData,
                       uint32_t aDataSize,
-                      Microseconds aTimestamp)
+                      Microseconds aTimestamp,
+                      Microseconds aDuration)
 {
   HRESULT hr;
   CComPtr<IMFSample> input = nullptr;
-  hr = CreateInputSample(aData, aDataSize, aTimestamp, &input);
+  hr = CreateInputSample(aData, aDataSize, aTimestamp, aDuration, &input);
   ENSURE(SUCCEEDED(hr) && input!=nullptr, hr);
 
   hr = mDecoder->ProcessInput(0, input, 0);
   if (hr == MF_E_NOTACCEPTING) {
     // MFT *already* has enough data to produce a sample. Retrieve it.
     LOG("ProcessInput returned MF_E_NOTACCEPTING\n");
     return MF_E_NOTACCEPTING;
   }
--- a/media/gmp-clearkey/0.1/WMFH264Decoder.h
+++ b/media/gmp-clearkey/0.1/WMFH264Decoder.h
@@ -25,17 +25,18 @@ class WMFH264Decoder {
 public:
   WMFH264Decoder();
   ~WMFH264Decoder();
 
   HRESULT Init(int32_t aCoreCount);
 
   HRESULT Input(const uint8_t* aData,
                 uint32_t aDataSize,
-                Microseconds aTimestamp);
+                Microseconds aTimestamp,
+                Microseconds aDuration);
 
   HRESULT Output(IMFSample** aOutput);
 
   HRESULT Reset();
 
   int32_t GetFrameWidth() const;
   int32_t GetFrameHeight() const;
   const IntRect& GetPictureRegion() const;
@@ -47,16 +48,17 @@ private:
 
   HRESULT SetDecoderInputType();
   HRESULT SetDecoderOutputType();
   HRESULT SendMFTMessage(MFT_MESSAGE_TYPE aMsg, UINT32 aData);
 
   HRESULT CreateInputSample(const uint8_t* aData,
                             uint32_t aDataSize,
                             Microseconds aTimestamp,
+                            Microseconds aDuration,
                             IMFSample** aOutSample);
 
   HRESULT CreateOutputSample(IMFSample** aOutSample);
 
   HRESULT GetOutputSample(IMFSample** aOutSample);
   HRESULT ConfigureVideoFrameGeometry(IMFMediaType* aMediaType);
 
   MFT_INPUT_STREAM_INFO mInputStreamInfo;
--- a/media/gmp-clearkey/0.1/WMFUtils.h
+++ b/media/gmp-clearkey/0.1/WMFUtils.h
@@ -114,18 +114,18 @@ typedef int64_t Microseconds;
 
 #ifdef ENSURE
 #undef ENSURE
 #endif
 
 #define ENSURE(condition, ret) \
 { if (!(condition)) { LOG("##condition## FAILED %S:%d\n", __FILE__, __LINE__); return ret; } }
 
-#define STATUS_SUCCEEDED(x) ((x) == Status::kSuccess)
-#define STATUS_FAILED(x) ((x) != Status::kSuccess)
+#define GMP_SUCCEEDED(x) ((x) == GMPNoErr)
+#define GMP_FAILED(x) ((x) != GMPNoErr)
 
 #define MFPLAT_FUNC(_func, _dllname) \
   extern decltype(::_func)* _func;
 #include "WMFSymbols.h"
 #undef MFPLAT_FUNC
 
 bool
 EnsureLibs();
--- a/media/gmp-clearkey/0.1/gmp-clearkey.cpp
+++ b/media/gmp-clearkey/0.1/gmp-clearkey.cpp
@@ -13,52 +13,73 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
-#include "ClearKeyCDM.h"
+#include "ClearKeyAsyncShutdown.h"
 #include "ClearKeySessionManager.h"
-// This include is required in order for content_decryption_module to work
-// on Unix systems.
-#include "stddef.h"
-#include "content_decryption_module.h"
+#include "gmp-api/gmp-async-shutdown.h"
+#include "gmp-api/gmp-decryption.h"
+#include "gmp-api/gmp-platform.h"
+
+#if defined(ENABLE_WMF)
+#include "WMFUtils.h"
+#include "VideoDecoder.h"
+#endif
 
-#ifdef ENABLE_WMF
-#include "WMFUtils.h"
-#endif // ENABLE_WMF
+#if defined(WIN32)
+#define GMP_EXPORT __declspec(dllexport)
+#else
+#define GMP_EXPORT __attribute__((visibility("default")))
+#endif
+
+static GMPPlatformAPI* sPlatform = nullptr;
+GMPPlatformAPI*
+GetPlatform()
+{
+  return sPlatform;
+}
 
 extern "C" {
 
-CDM_EXPORT
-void INITIALIZE_CDM_MODULE() {
-
+GMP_EXPORT GMPErr
+GMPInit(GMPPlatformAPI* aPlatformAPI)
+{
+  sPlatform = aPlatformAPI;
+  return GMPNoErr;
 }
 
-CDM_EXPORT
-void* CreateCdmInstance(int cdm_interface_version,
-                        const char* key_system,
-                        uint32_t key_system_size,
-                        GetCdmHostFunc get_cdm_host_func,
-                        void* user_data)
+GMP_EXPORT GMPErr
+GMPGetAPI(const char* aApiName, void* aHostAPI, void** aPluginAPI)
 {
-
-  CK_LOGE("ClearKey CreateCDMInstance");
+  CK_LOGD("ClearKey GMPGetAPI |%s|", aApiName);
+  assert(!*aPluginAPI);
 
-#ifdef ENABLE_WMF
-  if (!wmf::EnsureLibs()) {
-    CK_LOGE("Required libraries were not found");
-    return nullptr;
+  if (!strcmp(aApiName, GMP_API_DECRYPTOR)) {
+    *aPluginAPI = new ClearKeySessionManager();
+  }
+#if defined(ENABLE_WMF)
+ else if (!strcmp(aApiName, GMP_API_VIDEO_DECODER) &&
+             wmf::EnsureLibs()) {
+    *aPluginAPI = new VideoDecoder(static_cast<GMPVideoHost*>(aHostAPI));
   }
 #endif
+  else if (!strcmp(aApiName, GMP_API_ASYNC_SHUTDOWN)) {
+    *aPluginAPI = new ClearKeyAsyncShutdown(static_cast<GMPAsyncShutdownHost*> (aHostAPI));
+  } else {
+    CK_LOGE("GMPGetAPI couldn't resolve API name |%s|\n", aApiName);
+  }
 
-  cdm::Host_8* host = static_cast<cdm::Host_8*>(
-    get_cdm_host_func(cdm_interface_version, user_data));
-  ClearKeyCDM* clearKey = new ClearKeyCDM(host);
+  return *aPluginAPI ? GMPNoErr : GMPNotImplementedErr;
+}
 
-  CK_LOGE("Created ClearKeyCDM instance!");
+GMP_EXPORT GMPErr
+GMPShutdown(void)
+{
+  CK_LOGD("ClearKey GMPShutdown");
+  return GMPNoErr;
+}
 
-  return clearKey;
 }
-}
new file mode 100644
--- /dev/null
+++ b/media/gmp-clearkey/0.1/gmp-task-utils-generated.h
@@ -0,0 +1,1938 @@
+/*
+ * Copyright 2015, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RefCounted.h"
+
+// 0 arguments --
+template<typename M> class gmp_task_args_nm_0 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_0(M m) :
+    m_(m)  {}
+
+  void Run() {
+    m_();
+  }
+
+ private:
+  M m_;
+};
+
+
+
+// 0 arguments --
+template<typename M, typename R> class gmp_task_args_nm_0_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_0_ret(M m, R *r) :
+    m_(m), r_(r)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_();
+  }
+
+ private:
+  M m_;
+  R* r_;
+};
+
+
+
+// 0 arguments --
+template<typename C, typename M> class gmp_task_args_m_0 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_0(C o, M m) :
+    o_(o), m_(m)  {}
+
+  void Run() {
+    ((*o_).*m_)();
+  }
+
+ private:
+  C o_;
+  M m_;
+};
+
+
+
+// 0 arguments --
+template<typename C, typename M, typename R> class gmp_task_args_m_0_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_0_ret(C o, M m, R *r) :
+    o_(o), m_(m), r_(r)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)();
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+};
+
+
+
+// 1 arguments --
+template<typename M, typename A0> class gmp_task_args_nm_1 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_1(M m, A0 a0) :
+    m_(m), a0_(a0)  {}
+
+  void Run() {
+    m_(a0_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+};
+
+
+
+// 1 arguments --
+template<typename M, typename A0, typename R> class gmp_task_args_nm_1_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_1_ret(M m, A0 a0, R *r) :
+    m_(m), r_(r), a0_(a0)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+};
+
+
+
+// 1 arguments --
+template<typename C, typename M, typename A0> class gmp_task_args_m_1 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_1(C o, M m, A0 a0) :
+    o_(o), m_(m), a0_(a0)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+};
+
+
+
+// 1 arguments --
+template<typename C, typename M, typename A0, typename R> class gmp_task_args_m_1_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_1_ret(C o, M m, A0 a0, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+};
+
+
+
+// 2 arguments --
+template<typename M, typename A0, typename A1> class gmp_task_args_nm_2 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_2(M m, A0 a0, A1 a1) :
+    m_(m), a0_(a0), a1_(a1)  {}
+
+  void Run() {
+    m_(a0_, a1_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+};
+
+
+
+// 2 arguments --
+template<typename M, typename A0, typename A1, typename R> class gmp_task_args_nm_2_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_2_ret(M m, A0 a0, A1 a1, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+};
+
+
+
+// 2 arguments --
+template<typename C, typename M, typename A0, typename A1> class gmp_task_args_m_2 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_2(C o, M m, A0 a0, A1 a1) :
+    o_(o), m_(m), a0_(a0), a1_(a1)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+};
+
+
+
+// 2 arguments --
+template<typename C, typename M, typename A0, typename A1, typename R> class gmp_task_args_m_2_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_2_ret(C o, M m, A0 a0, A1 a1, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+};
+
+
+
+// 3 arguments --
+template<typename M, typename A0, typename A1, typename A2> class gmp_task_args_nm_3 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_3(M m, A0 a0, A1 a1, A2 a2) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+};
+
+
+
+// 3 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename R> class gmp_task_args_nm_3_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_3_ret(M m, A0 a0, A1 a1, A2 a2, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+};
+
+
+
+// 3 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2> class gmp_task_args_m_3 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_3(C o, M m, A0 a0, A1 a1, A2 a2) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+};
+
+
+
+// 3 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename R> class gmp_task_args_m_3_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_3_ret(C o, M m, A0 a0, A1 a1, A2 a2, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+};
+
+
+
+// 4 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3> class gmp_task_args_nm_4 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_4(M m, A0 a0, A1 a1, A2 a2, A3 a3) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+};
+
+
+
+// 4 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename R> class gmp_task_args_nm_4_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_4_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+};
+
+
+
+// 4 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3> class gmp_task_args_m_4 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_4(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+};
+
+
+
+// 4 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename R> class gmp_task_args_m_4_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_4_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+};
+
+
+
+// 5 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4> class gmp_task_args_nm_5 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_5(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+};
+
+
+
+// 5 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename R> class gmp_task_args_nm_5_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_5_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+};
+
+
+
+// 5 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4> class gmp_task_args_m_5 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_5(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+};
+
+
+
+// 5 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename R> class gmp_task_args_m_5_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_5_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+};
+
+
+
+// 6 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5> class gmp_task_args_nm_6 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_6(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+};
+
+
+
+// 6 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename R> class gmp_task_args_nm_6_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_6_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+};
+
+
+
+// 6 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5> class gmp_task_args_m_6 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_6(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+};
+
+
+
+// 6 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename R> class gmp_task_args_m_6_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_6_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+};
+
+
+
+// 7 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6> class gmp_task_args_nm_7 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_7(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+};
+
+
+
+// 7 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename R> class gmp_task_args_nm_7_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_7_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+};
+
+
+
+// 7 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6> class gmp_task_args_m_7 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_7(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+};
+
+
+
+// 7 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename R> class gmp_task_args_m_7_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_7_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+};
+
+
+
+// 8 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7> class gmp_task_args_nm_8 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_8(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+};
+
+
+
+// 8 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename R> class gmp_task_args_nm_8_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_8_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+};
+
+
+
+// 8 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7> class gmp_task_args_m_8 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_8(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+};
+
+
+
+// 8 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename R> class gmp_task_args_m_8_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_8_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+};
+
+
+
+// 9 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8> class gmp_task_args_nm_9 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_9(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+};
+
+
+
+// 9 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename R> class gmp_task_args_nm_9_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_9_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+};
+
+
+
+// 9 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8> class gmp_task_args_m_9 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_9(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+};
+
+
+
+// 9 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename R> class gmp_task_args_m_9_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_9_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+};
+
+
+
+// 10 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9> class gmp_task_args_nm_10 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_10(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+};
+
+
+
+// 10 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename R> class gmp_task_args_nm_10_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_10_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+};
+
+
+
+// 10 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9> class gmp_task_args_m_10 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_10(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+};
+
+
+
+// 10 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename R> class gmp_task_args_m_10_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_10_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+};
+
+
+
+// 11 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10> class gmp_task_args_nm_11 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_11(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+};
+
+
+
+// 11 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename R> class gmp_task_args_nm_11_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_11_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+};
+
+
+
+// 11 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10> class gmp_task_args_m_11 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_11(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+};
+
+
+
+// 11 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename R> class gmp_task_args_m_11_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_11_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+};
+
+
+
+// 12 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11> class gmp_task_args_nm_12 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_12(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+};
+
+
+
+// 12 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename R> class gmp_task_args_nm_12_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_12_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+};
+
+
+
+// 12 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11> class gmp_task_args_m_12 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_12(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+};
+
+
+
+// 12 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename R> class gmp_task_args_m_12_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_12_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+};
+
+
+
+// 13 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12> class gmp_task_args_nm_13 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_13(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+};
+
+
+
+// 13 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename R> class gmp_task_args_nm_13_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_13_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+};
+
+
+
+// 13 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12> class gmp_task_args_m_13 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_13(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+};
+
+
+
+// 13 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename R> class gmp_task_args_m_13_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_13_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+};
+
+
+
+// 14 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13> class gmp_task_args_nm_14 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_14(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+  A13 a13_;
+};
+
+
+
+// 14 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename R> class gmp_task_args_nm_14_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_nm_14_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+  A13 a13_;
+};
+
+
+
+// 14 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13> class gmp_task_args_m_14 : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_14(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+  A13 a13_;
+};
+
+
+
+// 14 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename R> class gmp_task_args_m_14_ret : public gmp_task_args_base {
+ public:
+  explicit gmp_task_args_m_14_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+  A13 a13_;
+};
+
+
+
+
+
+
+// 0 arguments --
+template<typename M>
+gmp_task_args_nm_0<M>* WrapTaskNM(M m) {
+  return new gmp_task_args_nm_0<M>
+    (m);
+}
+
+// 0 arguments --
+template<typename M, typename R>
+gmp_task_args_nm_0_ret<M, R>* WrapTaskNMRet(M m, R* r) {
+  return new gmp_task_args_nm_0_ret<M, R>
+    (m, r);
+}
+
+// 0 arguments --
+template<typename C, typename M>
+gmp_task_args_m_0<C, M>* WrapTask(C o, M m) {
+  return new gmp_task_args_m_0<C, M>
+    (o, m);
+}
+
+// 0 arguments --
+template<typename C, typename M, typename R>
+gmp_task_args_m_0_ret<C, M, R>* WrapTaskRet(C o, M m, R* r) {
+  return new gmp_task_args_m_0_ret<C, M, R>
+    (o, m, r);
+}
+
+// 1 arguments --
+template<typename M, typename A0>
+gmp_task_args_nm_1<M, A0>* WrapTaskNM(M m, A0 a0) {
+  return new gmp_task_args_nm_1<M, A0>
+    (m, a0);
+}
+
+// 1 arguments --
+template<typename M, typename A0, typename R>
+gmp_task_args_nm_1_ret<M, A0, R>* WrapTaskNMRet(M m, A0 a0, R* r) {
+  return new gmp_task_args_nm_1_ret<M, A0, R>
+    (m, a0, r);
+}
+
+// 1 arguments --
+template<typename C, typename M, typename A0>
+gmp_task_args_m_1<C, M, A0>* WrapTask(C o, M m, A0 a0) {
+  return new gmp_task_args_m_1<C, M, A0>
+    (o, m, a0);
+}
+
+// 1 arguments --
+template<typename C, typename M, typename A0, typename R>
+gmp_task_args_m_1_ret<C, M, A0, R>* WrapTaskRet(C o, M m, A0 a0, R* r) {
+  return new gmp_task_args_m_1_ret<C, M, A0, R>
+    (o, m, a0, r);
+}
+
+// 2 arguments --
+template<typename M, typename A0, typename A1>
+gmp_task_args_nm_2<M, A0, A1>* WrapTaskNM(M m, A0 a0, A1 a1) {
+  return new gmp_task_args_nm_2<M, A0, A1>
+    (m, a0, a1);
+}
+
+// 2 arguments --
+template<typename M, typename A0, typename A1, typename R>
+gmp_task_args_nm_2_ret<M, A0, A1, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, R* r) {
+  return new gmp_task_args_nm_2_ret<M, A0, A1, R>
+    (m, a0, a1, r);
+}
+
+// 2 arguments --
+template<typename C, typename M, typename A0, typename A1>
+gmp_task_args_m_2<C, M, A0, A1>* WrapTask(C o, M m, A0 a0, A1 a1) {
+  return new gmp_task_args_m_2<C, M, A0, A1>
+    (o, m, a0, a1);
+}
+
+// 2 arguments --
+template<typename C, typename M, typename A0, typename A1, typename R>
+gmp_task_args_m_2_ret<C, M, A0, A1, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, R* r) {
+  return new gmp_task_args_m_2_ret<C, M, A0, A1, R>
+    (o, m, a0, a1, r);
+}
+
+// 3 arguments --
+template<typename M, typename A0, typename A1, typename A2>
+gmp_task_args_nm_3<M, A0, A1, A2>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2) {
+  return new gmp_task_args_nm_3<M, A0, A1, A2>
+    (m, a0, a1, a2);
+}
+
+// 3 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename R>
+gmp_task_args_nm_3_ret<M, A0, A1, A2, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, R* r) {
+  return new gmp_task_args_nm_3_ret<M, A0, A1, A2, R>
+    (m, a0, a1, a2, r);
+}
+
+// 3 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2>
+gmp_task_args_m_3<C, M, A0, A1, A2>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2) {
+  return new gmp_task_args_m_3<C, M, A0, A1, A2>
+    (o, m, a0, a1, a2);
+}
+
+// 3 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename R>
+gmp_task_args_m_3_ret<C, M, A0, A1, A2, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, R* r) {
+  return new gmp_task_args_m_3_ret<C, M, A0, A1, A2, R>
+    (o, m, a0, a1, a2, r);
+}
+
+// 4 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3>
+gmp_task_args_nm_4<M, A0, A1, A2, A3>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3) {
+  return new gmp_task_args_nm_4<M, A0, A1, A2, A3>
+    (m, a0, a1, a2, a3);
+}
+
+// 4 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename R>
+gmp_task_args_nm_4_ret<M, A0, A1, A2, A3, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, R* r) {
+  return new gmp_task_args_nm_4_ret<M, A0, A1, A2, A3, R>
+    (m, a0, a1, a2, a3, r);
+}
+
+// 4 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3>
+gmp_task_args_m_4<C, M, A0, A1, A2, A3>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3) {
+  return new gmp_task_args_m_4<C, M, A0, A1, A2, A3>
+    (o, m, a0, a1, a2, a3);
+}
+
+// 4 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename R>
+gmp_task_args_m_4_ret<C, M, A0, A1, A2, A3, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, R* r) {
+  return new gmp_task_args_m_4_ret<C, M, A0, A1, A2, A3, R>
+    (o, m, a0, a1, a2, a3, r);
+}
+
+// 5 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4>
+gmp_task_args_nm_5<M, A0, A1, A2, A3, A4>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+  return new gmp_task_args_nm_5<M, A0, A1, A2, A3, A4>
+    (m, a0, a1, a2, a3, a4);
+}
+
+// 5 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename R>
+gmp_task_args_nm_5_ret<M, A0, A1, A2, A3, A4, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R* r) {
+  return new gmp_task_args_nm_5_ret<M, A0, A1, A2, A3, A4, R>
+    (m, a0, a1, a2, a3, a4, r);
+}
+
+// 5 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4>
+gmp_task_args_m_5<C, M, A0, A1, A2, A3, A4>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+  return new gmp_task_args_m_5<C, M, A0, A1, A2, A3, A4>
+    (o, m, a0, a1, a2, a3, a4);
+}
+
+// 5 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename R>
+gmp_task_args_m_5_ret<C, M, A0, A1, A2, A3, A4, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R* r) {
+  return new gmp_task_args_m_5_ret<C, M, A0, A1, A2, A3, A4, R>
+    (o, m, a0, a1, a2, a3, a4, r);
+}
+
+// 6 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5>
+gmp_task_args_nm_6<M, A0, A1, A2, A3, A4, A5>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) {
+  return new gmp_task_args_nm_6<M, A0, A1, A2, A3, A4, A5>
+    (m, a0, a1, a2, a3, a4, a5);
+}
+
+// 6 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename R>
+gmp_task_args_nm_6_ret<M, A0, A1, A2, A3, A4, A5, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R* r) {
+  return new gmp_task_args_nm_6_ret<M, A0, A1, A2, A3, A4, A5, R>
+    (m, a0, a1, a2, a3, a4, a5, r);
+}
+
+// 6 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5>
+gmp_task_args_m_6<C, M, A0, A1, A2, A3, A4, A5>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) {
+  return new gmp_task_args_m_6<C, M, A0, A1, A2, A3, A4, A5>
+    (o, m, a0, a1, a2, a3, a4, a5);
+}
+
+// 6 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename R>
+gmp_task_args_m_6_ret<C, M, A0, A1, A2, A3, A4, A5, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R* r) {
+  return new gmp_task_args_m_6_ret<C, M, A0, A1, A2, A3, A4, A5, R>
+    (o, m, a0, a1, a2, a3, a4, a5, r);
+}
+
+// 7 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
+gmp_task_args_nm_7<M, A0, A1, A2, A3, A4, A5, A6>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) {
+  return new gmp_task_args_nm_7<M, A0, A1, A2, A3, A4, A5, A6>
+    (m, a0, a1, a2, a3, a4, a5, a6);
+}
+
+// 7 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename R>
+gmp_task_args_nm_7_ret<M, A0, A1, A2, A3, A4, A5, A6, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R* r) {
+  return new gmp_task_args_nm_7_ret<M, A0, A1, A2, A3, A4, A5, A6, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, r);
+}
+
+// 7 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
+gmp_task_args_m_7<C, M, A0, A1, A2, A3, A4, A5, A6>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) {
+  return new gmp_task_args_m_7<C, M, A0, A1, A2, A3, A4, A5, A6>
+    (o, m, a0, a1, a2, a3, a4, a5, a6);
+}
+
+// 7 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename R>
+gmp_task_args_m_7_ret<C, M, A0, A1, A2, A3, A4, A5, A6, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R* r) {
+  return new gmp_task_args_m_7_ret<C, M, A0, A1, A2, A3, A4, A5, A6, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, r);
+}
+
+// 8 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
+gmp_task_args_nm_8<M, A0, A1, A2, A3, A4, A5, A6, A7>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) {
+  return new gmp_task_args_nm_8<M, A0, A1, A2, A3, A4, A5, A6, A7>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7);
+}
+
+// 8 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename R>
+gmp_task_args_nm_8_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R* r) {
+  return new gmp_task_args_nm_8_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, r);
+}
+
+// 8 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
+gmp_task_args_m_8<C, M, A0, A1, A2, A3, A4, A5, A6, A7>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) {
+  return new gmp_task_args_m_8<C, M, A0, A1, A2, A3, A4, A5, A6, A7>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7);
+}
+
+// 8 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename R>
+gmp_task_args_m_8_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R* r) {
+  return new gmp_task_args_m_8_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, r);
+}
+
+// 9 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
+gmp_task_args_nm_9<M, A0, A1, A2, A3, A4, A5, A6, A7, A8>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) {
+  return new gmp_task_args_nm_9<M, A0, A1, A2, A3, A4, A5, A6, A7, A8>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8);
+}
+
+// 9 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename R>
+gmp_task_args_nm_9_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R* r) {
+  return new gmp_task_args_nm_9_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, r);
+}
+
+// 9 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
+gmp_task_args_m_9<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) {
+  return new gmp_task_args_m_9<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8);
+}
+
+// 9 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename R>
+gmp_task_args_m_9_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R* r) {
+  return new gmp_task_args_m_9_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, r);
+}
+
+// 10 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>
+gmp_task_args_nm_10<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) {
+  return new gmp_task_args_nm_10<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+}
+
+// 10 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename R>
+gmp_task_args_nm_10_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R* r) {
+  return new gmp_task_args_nm_10_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, r);
+}
+
+// 10 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>
+gmp_task_args_m_10<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) {
+  return new gmp_task_args_m_10<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+}
+
+// 10 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename R>
+gmp_task_args_m_10_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R* r) {
+  return new gmp_task_args_m_10_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, r);
+}
+
+// 11 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10>
+gmp_task_args_nm_11<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) {
+  return new gmp_task_args_nm_11<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
+}
+
+// 11 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename R>
+gmp_task_args_nm_11_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R* r) {
+  return new gmp_task_args_nm_11_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, r);
+}
+
+// 11 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10>
+gmp_task_args_m_11<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) {
+  return new gmp_task_args_m_11<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
+}
+
+// 11 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename R>
+gmp_task_args_m_11_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R* r) {
+  return new gmp_task_args_m_11_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, r);
+}
+
+// 12 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11>
+gmp_task_args_nm_12<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) {
+  return new gmp_task_args_nm_12<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
+}
+
+// 12 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename R>
+gmp_task_args_nm_12_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R* r) {
+  return new gmp_task_args_nm_12_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, r);
+}
+
+// 12 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11>
+gmp_task_args_m_12<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) {
+  return new gmp_task_args_m_12<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
+}
+
+// 12 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename R>
+gmp_task_args_m_12_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R* r) {
+  return new gmp_task_args_m_12_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, r);
+}
+
+// 13 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12>
+gmp_task_args_nm_13<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) {
+  return new gmp_task_args_nm_13<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
+}
+
+// 13 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename R>
+gmp_task_args_nm_13_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R* r) {
+  return new gmp_task_args_nm_13_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, r);
+}
+
+// 13 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12>
+gmp_task_args_m_13<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) {
+  return new gmp_task_args_m_13<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
+}
+
+// 13 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename R>
+gmp_task_args_m_13_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R* r) {
+  return new gmp_task_args_m_13_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, r);
+}
+
+// 14 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13>
+gmp_task_args_nm_14<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) {
+  return new gmp_task_args_nm_14<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13);
+}
+
+// 14 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename R>
+gmp_task_args_nm_14_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R* r) {
+  return new gmp_task_args_nm_14_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, r);
+}
+
+// 14 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13>
+gmp_task_args_m_14<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) {
+  return new gmp_task_args_m_14<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13);
+}
+
+// 14 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename R>
+gmp_task_args_m_14_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R* r) {
+  return new gmp_task_args_m_14_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, r);
+}
+
+class RefCountTaskWrapper : public gmp_task_args_base {
+public:
+  RefCountTaskWrapper(GMPTask* aTask, RefCounted* aRefCounted)
+    : mTask(aTask)
+    , mRefCounted(aRefCounted)
+  {}
+  virtual void Run() override {
+    mTask->Run();
+  }
+  virtual void Destroy() override {
+    mTask->Destroy();
+    gmp_task_args_base::Destroy();
+  }
+private:
+  ~RefCountTaskWrapper() {}
+
+  GMPTask* mTask;
+  RefPtr<RefCounted> mRefCounted;
+};
+
+template<typename Type, typename Method, typename... Args>
+GMPTask*
+WrapTaskRefCounted(Type* aType, Method aMethod, Args&&... args)
+{
+  GMPTask* t = WrapTask(aType, aMethod, std::forward<Args>(args)...);
+  return new RefCountTaskWrapper(t, aType);
+}
new file mode 100644
--- /dev/null
+++ b/media/gmp-clearkey/0.1/gmp-task-utils.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Original author: ekr@rtfm.com
+
+#ifndef gmp_task_utils_h_
+#define gmp_task_utils_h_
+
+#include "gmp-api/gmp-platform.h"
+
+class gmp_task_args_base : public GMPTask {
+public:
+  virtual void Destroy() { delete this; }
+  virtual void Run() = 0;
+};
+
+// The generated file contains four major function templates
+// (in variants for arbitrary numbers of arguments up to 10,
+// which is why it is machine generated). The four templates
+// are:
+//
+// WrapTask(o, m, ...) -- wraps a member function m of an object ptr o
+// WrapTaskRet(o, m, ..., r) -- wraps a member function m of an object ptr o
+//                                  the function returns something that can
+//                                  be assigned to *r
+// WrapTaskNM(f, ...) -- wraps a function f
+// WrapTaskNMRet(f, ..., r) -- wraps a function f that returns something
+//                                 that can be assigned to *r
+//
+// All of these template functions return a GMPTask* which can be passed
+// to DispatchXX().
+#include "gmp-task-utils-generated.h"
+
+#endif // gmp_task_utils_h_
--- a/media/gmp-clearkey/0.1/moz.build
+++ b/media/gmp-clearkey/0.1/moz.build
@@ -6,54 +6,57 @@
 
 SharedLibrary('clearkey')
 
 FINAL_TARGET = 'dist/bin/gmp-clearkey/0.1'
 
 FINAL_TARGET_PP_FILES += ['manifest.json.in']
 
 UNIFIED_SOURCES += [
+    'ClearKeyAsyncShutdown.cpp',
     'ClearKeyBase64.cpp',
-    'ClearKeyCDM.cpp',
     'ClearKeyDecryptionManager.cpp',
     'ClearKeyPersistence.cpp',
     'ClearKeySession.cpp',
     'ClearKeySessionManager.cpp',
     'ClearKeyStorage.cpp',
     'ClearKeyUtils.cpp',
     'gmp-clearkey.cpp',
 ]
 
 SOURCES += [
     'openaes/oaes_lib.c',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     UNIFIED_SOURCES += [
+        'AnnexB.cpp',
         'VideoDecoder.cpp',
         'WMFH264Decoder.cpp',
     ]
 
     SOURCES += [
         'WMFUtils.cpp',
     ]
 
     OS_LIBS += [
         'mfuuid',
     ]
 
     DEFINES['ENABLE_WMF'] = True
 
-
-DEFINES['CDM_IMPLEMENTATION'] = True
-
 TEST_DIRS += [
     'gtest',
 ]
 
+
+LOCAL_INCLUDES += [
+    '/dom/media/gmp',
+]
+
 DISABLE_STL_WRAPPING = True
 DEFINES['MOZ_NO_MOZALLOC'] = True
 
 USE_LIBS += ['psshparser']
 
 # Suppress warnings in third-party code.
 if CONFIG['GNU_CXX']:
     CFLAGS += [