Bug 1318965 - Converts gmp-clearkey to use Chromium ContentDecryptionModule8 interface used by widevine r?cpearce draft
authorJay Harris <jharris@mozilla.com>
Fri, 16 Dec 2016 12:15:43 +1300
changeset 452074 47bccc70263d7c945b4ef30d7357dc3f40387d76
parent 452073 2f9b09cb8e15a29d9698a0b2512fc007ec654a3d
child 452075 a16105d47af7f1e8f8e80894b5a9e06a31404835
push id39320
push userbmo:jharris@mozilla.com
push dateWed, 21 Dec 2016 05:00:07 +0000
reviewerscpearce
bugs1318965
milestone53.0a1
Bug 1318965 - Converts gmp-clearkey to use Chromium ContentDecryptionModule8 interface used by widevine r?cpearce MozReview-Commit-ID: 385PPB4WC1q
dom/media/gmp/moz.build
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,16 +67,17 @@ 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',
     ]
@@ -114,17 +115,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 += [
deleted file mode 100644
--- a/media/gmp-clearkey/0.1/AnnexB.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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);
-}
deleted file mode 100644
--- a/media/gmp-clearkey/0.1/AnnexB.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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__
deleted file mode 100644
--- a/media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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));
-}
deleted file mode 100644
--- a/media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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__
new file mode 100644
--- /dev/null
+++ b/media/gmp-clearkey/0.1/ClearKeyCDM.cpp
@@ -0,0 +1,175 @@
+#include "ClearKeyCDM.h"
+
+#include "ClearKeyUtils.h"
+
+using namespace cdm;
+
+ClearKeyCDM::ClearKeyCDM(Host_8 * aHost)
+{
+  mHost = aHost;
+}
+
+void ClearKeyCDM::Initialize(bool aAllowDistinctiveIdentifier,
+                             bool aAllowPersistentState) {
+  mSessionManager = new ClearKeySessionManager();
+  mSessionManager->Init(mHost,
+                        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) {
+  // No equivalent in ClearKeySessionManager or VideoDecoder, so not
+  // 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
+  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) {
+  if (aDecoderType == StreamType::kStreamTypeVideo) {
+#ifdef ENABLE_WMF
+    mVideoDecoder->Reset();
+#endif
+  }
+}
+
+void
+ClearKeyCDM::ResetDecoder(StreamType aDecoderType) {
+  if (aDecoderType == StreamType::kStreamTypeVideo) {
+#ifdef ENABLE_WMF
+    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
+  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
+}
+
+
new file mode 100644
--- /dev/null
+++ b/media/gmp-clearkey/0.1/ClearKeyCDM.h
@@ -0,0 +1,98 @@
+#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:
+  ClearKeySessionManager* mSessionManager;
+#ifdef ENABLE_WMF
+  VideoDecoder* mVideoDecoder = nullptr;
+#endif
+
+protected:
+  cdm::Host_8* mHost;
+
+public:
+  explicit ClearKeyCDM(cdm::Host_8* mHost);
+
+  virtual void Initialize(bool aAllowDistinctiveIdentifier,
+                          bool aAllowPersistentState) override;
+
+  virtual void SetServerCertificate(uint32_t aPromiseId,
+                                    const uint8_t* aServerCertificateData,
+                                    uint32_t aServerCertificateDataSize)
+                                    override;
+
+  virtual void CreateSessionAndGenerateRequest(uint32_t aPromiseId,
+                                               cdm::SessionType aSessionType,
+                                               cdm::InitDataType aInitDataType,
+                                               const uint8_t* aInitData,
+                                               uint32_t aInitDataSize)
+                                               override;
+
+  virtual void LoadSession(uint32_t aPromiseId,
+                           cdm::SessionType aSessionType,
+                           const char* aSessionId,
+                           uint32_t aSessionIdSize) override;
+
+  virtual void UpdateSession(uint32_t aPromiseId,
+                             const char* aSessionId,
+                             uint32_t aSessionIdSize,
+                             const uint8_t* aResponse,
+                             uint32_t aResponseSize) override;
+
+  virtual void CloseSession(uint32_t aPromiseId,
+                            const char* aSessionId,
+                            uint32_t aSessionIdSize) override;
+
+  virtual void RemoveSession(uint32_t aPromiseId,
+                             const char* aSessionId,
+                             uint32_t aSessionIdSize) override;
+
+  virtual void TimerExpired(void* aContext) override;
+
+  virtual cdm::Status Decrypt(const cdm::InputBuffer& aEncryptedBuffer,
+                              cdm::DecryptedBlock* aDecryptedBuffer) override;
+
+  virtual cdm::Status InitializeAudioDecoder(
+    const cdm::AudioDecoderConfig& aAudioDecoderConfig) override;
+
+  virtual cdm::Status InitializeVideoDecoder(
+    const cdm::VideoDecoderConfig& aVideoDecoderConfig) override;
+
+  virtual void DeinitializeDecoder(cdm::StreamType aDecoderType) override;
+
+  virtual void ResetDecoder(cdm::StreamType aDecoderType) override;
+
+  virtual cdm::Status DecryptAndDecodeFrame(
+    const cdm::InputBuffer& aEncryptedBuffer,
+    cdm::VideoFrame* aVideoFrame) override;
+
+  virtual cdm::Status DecryptAndDecodeSamples(
+    const cdm::InputBuffer& aEncryptedBuffer,
+    cdm::AudioFrames* aAudioFrame) override;
+
+  virtual void OnPlatformChallengeResponse(
+    const cdm::PlatformChallengeResponse& aResponse) override;
+
+  virtual void
+    OnQueryOutputProtectionStatus(
+      cdm::QueryResult aResult,
+      uint32_t aLinkMask,
+      uint32_t aOutputProtectionMask) override;
+
+  virtual 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,45 +9,49 @@
  *
  * 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 "gmp-api/gmp-decryption.h"
+#include "psshparser/PsshParser.h"
+
+#include <assert.h>
 #include <string.h>
 #include <vector>
 
-#include "ClearKeyDecryptionManager.h"
-#include "psshparser/PsshParser.h"
-#include "gmp-api/gmp-decryption.h"
-#include <assert.h>
+using namespace cdm;
 
 class ClearKeyDecryptor : public RefCounted
 {
 public:
   ClearKeyDecryptor();
 
   void InitKey(const Key& aKey);
   bool HasKey() const { return !!mKey.size(); }
 
-  GMPErr Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
+  Status 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;
@@ -68,24 +72,26 @@ 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_LOGD("ClearKeyDecryptionManager::IsExpectingKeyForId %08x...", *(uint32_t*)&aKeyId[0]);
+  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");
@@ -98,26 +104,32 @@ ClearKeyDecryptionManager::GetDecryption
 {
   assert(HasKeyForKeyId(aKeyId));
   return mDecryptors[aKeyId]->DecryptionKey();
 }
 
 void
 ClearKeyDecryptionManager::InitKey(KeyId aKeyId, Key aKey)
 {
-  CK_LOGD("ClearKeyDecryptionManager::InitKey %08x...", *(uint32_t*)&aKeyId[0]);
+  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 %08x...", *(uint32_t*)&aKeyId[0]);
+  CK_LOGD("ClearKeyDecryptionManager::ExpectKeyId %08x...",
+          *(uint32_t*)&aKeyId[0]);
   if (!HasSeenKeyId(aKeyId)) {
     mDecryptors[aKeyId] = new ClearKeyDecryptor();
   }
   mDecryptors[aKeyId]->AddRef();
 }
 
 void
 ClearKeyDecryptionManager::ReleaseKeyId(KeyId aKeyId)
@@ -126,33 +138,41 @@ ClearKeyDecryptionManager::ReleaseKeyId(
   assert(HasSeenKeyId(aKeyId));
 
   ClearKeyDecryptor* decryptor = mDecryptors[aKeyId];
   if (!decryptor->Release()) {
     mDecryptors.erase(aKeyId);
   }
 }
 
-GMPErr
+Status
 ClearKeyDecryptionManager::Decrypt(std::vector<uint8_t>& aBuffer,
                                    const CryptoMetaData& aMetadata)
 {
   return Decrypt(&aBuffer[0], aBuffer.size(), aMetadata);
 }
 
-GMPErr
+Status
 ClearKeyDecryptionManager::Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
                                    const CryptoMetaData& aMetadata)
 {
   CK_LOGD("ClearKeyDecryptionManager::Decrypt");
   if (!HasKeyForKeyId(aMetadata.mKeyId)) {
-    return GMPNoKeyErr;
+    CK_LOGARRAY("Unable to find decryptor for: ",
+                aMetadata.mKeyId.data(),
+                aMetadata.mKeyId.size());
+    return Status::kNoKey;
   }
 
-  return mDecryptors[aMetadata.mKeyId]->Decrypt(aBuffer, aBufferSize, aMetadata);
+  CK_LOGARRAY("Found decryptor for: ",
+              aMetadata.mKeyId.data(),
+              aMetadata.mKeyId.size());
+  return mDecryptors[aMetadata.mKeyId]->Decrypt(aBuffer,
+                                                aBufferSize,
+                                                aMetadata);
 }
 
 ClearKeyDecryptor::ClearKeyDecryptor()
 {
   CK_LOGD("ClearKeyDecryptor ctor");
 }
 
 ClearKeyDecryptor::~ClearKeyDecryptor()
@@ -165,17 +185,17 @@ ClearKeyDecryptor::~ClearKeyDecryptor()
 }
 
 void
 ClearKeyDecryptor::InitKey(const Key& aKey)
 {
   mKey = aKey;
 }
 
-GMPErr
+Status
 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);
 
@@ -184,17 +204,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 GMPCryptoErr;
+        return Status::kNeedMoreData;
       }
 
       memcpy(iter, data, cipherBytes);
 
       data += cipherBytes;
       iter += cipherBytes;
     }
 
@@ -222,10 +242,10 @@ ClearKeyDecryptor::Decrypt(uint8_t* aBuf
 
       data += cipherBytes;
       iter += cipherBytes;
     }
   } else {
     memcpy(aBuffer, &tmp[0], aBufferSize);
   }
 
-  return GMPNoErr;
+  return Status::kSuccess;
 }
--- a/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.h
+++ b/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.h
@@ -12,59 +12,69 @@
  * 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 "ClearKeyUtils.h"
-#include "RefCounted.h"
+#include <map>
 
 class ClearKeyDecryptor;
 
 class CryptoMetaData {
 public:
   CryptoMetaData() {}
 
-  explicit CryptoMetaData(const GMPEncryptedBufferMetadata* aCrypto)
+  explicit CryptoMetaData(const cdm::InputBuffer* aInputBuffer)
   {
-    Init(aCrypto);
+    Init(aInputBuffer);
   }
 
-  void Init(const GMPEncryptedBufferMetadata* aCrypto)
+  void Init(const cdm::InputBuffer* aInputBuffer)
   {
-    if (!aCrypto) {
+    if (aInputBuffer == nullptr) {
       assert(!IsValid());
       return;
     }
-    Assign(mKeyId, aCrypto->KeyId(), aCrypto->KeyIdSize());
-    Assign(mIV, aCrypto->IV(), aCrypto->IVSize());
-    Assign(mClearBytes, aCrypto->ClearBytes(), aCrypto->NumSubsamples());
-    Assign(mCipherBytes, aCrypto->CipherBytes(), aCrypto->NumSubsamples());
+
+    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) {
+      cdm::SubsampleEntry subsample = aInputBuffer->subsamples[i];
+
+      mCipherBytes.push_back(subsample.cipher_bytes);
+      mClearBytes.push_back(subsample.clear_bytes);
+    }
   }
 
   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<uint16_t> mClearBytes;
+  std::vector<uint32_t> mClearBytes;
   std::vector<uint32_t> mCipherBytes;
 };
 
 class ClearKeyDecryptionManager : public RefCounted
 {
 private:
   ClearKeyDecryptionManager();
   ~ClearKeyDecryptionManager();
@@ -80,22 +90,20 @@ 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*.
-  GMPErr Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
+  cdm::Status Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
                  const CryptoMetaData& aMetadata);
-  GMPErr Decrypt(std::vector<uint8_t>& aBuffer,
+  cdm::Status 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,251 +10,116 @@
  * 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 <assert.h>
 #include <set>
-#include <vector>
+#include <stdint.h>
 #include <sstream>
-#include <assert.h>
+#include <string.h>
+#include <vector>
 
 using namespace std;
+using namespace cdm;
 
+// TODO load persistent session ids from GMP storage
 // Whether we've loaded the persistent session ids from GMPStorage yet.
 enum PersistentKeyState {
   UNINITIALIZED,
   LOADING,
   LOADED
 };
-static PersistentKeyState sPersistentKeyState = UNINITIALIZED;
+//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;
 
-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();
-
-  for (size_t i = 0; i < sTasksBlockedOnSessionIdLoad.size(); i++) {
-    sTasksBlockedOnSessionIdLoad[i]->Run();
-    sTasksBlockedOnSessionIdLoad[i]->Destroy();
-  }
-  sTasksBlockedOnSessionIdLoad.clear();
-}
+// TODO Find out what to do with this
+//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();
+//
+//  for (size_t i = 0; i < sTasksBlockedOnSessionIdLoad.size(); i++) {
+//    sTasksBlockedOnSessionIdLoad[i]->Run();
+//    sTasksBlockedOnSessionIdLoad[i]->Destroy();
+//  }
+//  sTasksBlockedOnSessionIdLoad.clear();
+//}
 
 /* static */ void
 ClearKeyPersistence::EnsureInitialized()
 {
-  if (sPersistentKeyState == UNINITIALIZED) {
-    sPersistentKeyState = LOADING;
-    if (GMP_FAILED(EnumRecordNames(&ReadAllRecordsFromIterator))) {
-      sPersistentKeyState = LOADED;
-    }
-  }
+  // TODO not sure what to do with this
+  //if (sPersistentKeyState == UNINITIALIZED) {
+  //  sPersistentKeyState = LOADING;
+  //  if (GMP_FAILED(EnumRecordNames(&ReadAllRecordsFromIterator))) {
+  //    sPersistentKeyState = LOADED;
+  //  }
+  //}
 }
 
 /* static */ string
-ClearKeyPersistence::GetNewSessionId(GMPSessionType aSessionType)
+ClearKeyPersistence::GetNewSessionId(SessionType aSessionType)
 {
   static uint32_t sNextSessionId = 1;
 
   // Ensure we don't re-use a session id that was persisted.
   while (Contains(sPersistentSessionIds, sNextSessionId)) {
     sNextSessionId++;
   }
 
   string sessionId;
   stringstream ss;
   ss << sNextSessionId;
   ss >> sessionId;
 
-  if (aSessionType == kGMPPersistentSession) {
+  if (aSessionType == SessionType::kPersistentLicense) {
     sPersistentSessionIds.insert(sNextSessionId);
   }
 
   sNextSessionId++;
 
   return sessionId;
 }
 
-
-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)
-{
-  if (sPersistentKeyState >= LOADED)  {
-    return false;
-  }
-  GMPTask* t = new CreateSessionTask(aInstance,
-                                     aCreateSessionToken,
-                                     aPromiseId,
-                                     aInitDataType,
-                                     aInitData,
-                                     aInitDataSize,
-                                     aSessionType);
-  sTasksBlockedOnSessionIdLoad.push_back(t);
-  return true;
-}
-
-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)
-{
-  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)
-  {
-  }
-
-  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)
+ClearKeyPersistence::PersistentSessionRemoved(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,42 +12,30 @@
  * 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 "gmp-api/gmp-decryption.h"
+
 #include <string>
-#include "gmp-api/gmp-decryption.h"
 
 class ClearKeySessionManager;
 
 class ClearKeyPersistence {
 public:
   static void EnsureInitialized();
 
-  static std::string GetNewSessionId(GMPSessionType aSessionType);
-
-  static bool DeferCreateSessionIfNotReady(ClearKeySessionManager* aInstance,
-                                           uint32_t aCreateSessionToken,
-                                           uint32_t aPromiseId,
-                                           const std::string& aInitDataType,
-                                           const uint8_t* aInitData,
-                                           uint32_t aInitDataSize,
-                                           GMPSessionType aSessionType);
-
-  static bool DeferLoadSessionIfNotReady(ClearKeySessionManager* aInstance,
-                                         uint32_t aPromiseId,
-                                         const char* aSessionId,
-                                         uint32_t aSessionIdLength);
+  static std::string GetNewSessionId(cdm::SessionType aSessionType);
 
   static bool IsPersistentSessionId(const std::string& aSid);
 
-  static void LoadSessionData(ClearKeySessionManager* aInstance,
-                              const std::string& aSid,
-                              uint32_t aPromiseId);
-
-  static void PersistentSessionRemoved(const std::string& aSid);
+  static void PersistentSessionRemoved(std::string& aSid);
 };
 
 #endif // __ClearKeyPersistence_h__
--- a/media/gmp-clearkey/0.1/ClearKeySession.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeySession.cpp
@@ -14,79 +14,86 @@
  * limitations under the License.
  */
 
 #include "BigEndian.h"
 #include "ClearKeyDecryptionManager.h"
 #include "ClearKeySession.h"
 #include "ClearKeyUtils.h"
 #include "ClearKeyStorage.h"
+#include "gmp-api/gmp-decryption.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,
-                                 GMPDecryptorCallback* aCallback,
-                                 GMPSessionType aSessionType)
+                                 Host_8* aHost,
+                                 SessionType aSessionType)
   : mSessionId(aSessionId)
-  , mCallback(aCallback)
+  , mHost(aHost)
   , mSessionType(aSessionType)
 {
   CK_LOGD("ClearKeySession ctor %p", this);
 }
 
 ClearKeySession::~ClearKeySession()
 {
   CK_LOGD("ClearKeySession dtor %p", this);
 
-  std::vector<GMPMediaKeyInfo> key_infos;
+  std::vector<KeyInformation> keyInfos;
   for (const KeyId& keyId : mKeyIds) {
     assert(ClearKeyDecryptionManager::Get()->HasSeenKeyId(keyId));
     ClearKeyDecryptionManager::Get()->ReleaseKeyId(keyId);
-    key_infos.push_back(GMPMediaKeyInfo(&keyId[0], keyId.size(), kGMPUnknown));
+
+    KeyInformation keyInfo = KeyInformation();
+    keyInfo.key_id = keyId.data();
+    keyInfo.key_id_size = keyId.size();
+    keyInfo.status = KeyStatus::kReleased;
+    keyInfos.push_back(keyInfo);
   }
-  mCallback->BatchedKeyStatusChanged(&mSessionId[0], mSessionId.size(),
-                                     key_infos.data(), key_infos.size());
+
+  mHost->OnSessionKeysChange(mSessionId.data(),
+    mSessionId.size(),
+    false,
+    keyInfos.data(),
+    keyInfos.size());
 }
 
-void
-ClearKeySession::Init(uint32_t aCreateSessionToken,
-                      uint32_t aPromiseId,
-                      const std::string& aInitDataType,
+bool
+ClearKeySession::Init(InitDataType aInitDataType,
                       const uint8_t* aInitData, uint32_t aInitDataSize)
 {
   CK_LOGD("ClearKeySession::Init");
 
-  if (aInitDataType == "cenc") {
+  if (aInitDataType == InitDataType::kCenc) {
     ParseCENCInitData(aInitData, aInitDataSize, mKeyIds);
-  } else if (aInitDataType == "keyids") {
+  } else if (aInitDataType == InitDataType::kKeyIds) {
     ClearKeyUtils::ParseKeyIdsInitData(aInitData, aInitDataSize, mKeyIds);
-  } else if (aInitDataType == "webm" && aInitDataSize <= kMaxWebmInitDataSize) {
+  } else if (aInitDataType == InitDataType::kWebM
+    && 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 there was an initialization error
   if (!mKeyIds.size()) {
-    const char message[] = "Couldn't parse init data";
-    mCallback->RejectPromise(aPromiseId, kGMPTypeError, message, strlen(message));
-    return;
+    return false;
   }
 
-  mCallback->SetSessionId(aCreateSessionToken, &mSessionId[0], mSessionId.length());
-
-  mCallback->ResolvePromise(aPromiseId);
+  return true;
 }
 
-GMPSessionType
+SessionType
 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,46 +13,51 @@
  * 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,
-                           GMPDecryptorCallback* aCallback,
-                           GMPSessionType aSessionType);
+                           cdm::Host_8* aHost,
+                           cdm::SessionType aSessionType);
 
   ~ClearKeySession();
 
   const std::vector<KeyId>& GetKeyIds() const { return mKeyIds; }
 
-  void Init(uint32_t aCreateSessionToken,
-            uint32_t aPromiseId,
-            const string& aInitDataType,
+  bool Init(cdm::InitDataType aInitDataType,
             const uint8_t* aInitData, uint32_t aInitDataSize);
 
-  GMPSessionType Type() const;
+  cdm::SessionType Type() const;
 
   void AddKeyId(const KeyId& aKeyId);
 
   const std::string& Id() const { return mSessionId; }
 
 private:
   const std::string mSessionId;
   std::vector<KeyId> mKeyIds;
 
-  GMPDecryptorCallback* mCallback;
-  const GMPSessionType mSessionType;
+  cdm::Host_8* mHost;
+  const cdm::SessionType mSessionType;
 };
 
 #endif // __ClearKeySession_h__
--- a/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp
@@ -9,98 +9,106 @@
  *
  * 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"
-#include "gmp-task-utils.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 <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
 
 using namespace std;
+using namespace cdm;
 
 ClearKeySessionManager::ClearKeySessionManager()
   : mDecryptionManager(ClearKeyDecryptionManager::Get())
 {
   CK_LOGD("ClearKeySessionManager ctor %p", this);
   AddRef();
-
-  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(GMPDecryptorCallback* aCallback,
+ClearKeySessionManager::Init(Host_8* aHost,
                              bool aDistinctiveIdentifierAllowed,
                              bool aPersistentStateAllowed)
 {
   CK_LOGD("ClearKeySessionManager::Init");
-  mCallback = aCallback;
+  mHost = aHost;
   ClearKeyPersistence::EnsureInitialized();
 }
 
 void
-ClearKeySessionManager::CreateSession(uint32_t aCreateSessionToken,
-                                      uint32_t aPromiseId,
-                                      const char* aInitDataType,
-                                      uint32_t aInitDataTypeSize,
+ClearKeySessionManager::CreateSession(uint32_t aPromiseId,
+                                      InitDataType aInitDataType,
                                       const uint8_t* aInitData,
                                       uint32_t aInitDataSize,
-                                      GMPSessionType aSessionType)
+                                      SessionType aSessionType)
 {
   CK_LOGD("ClearKeySessionManager::CreateSession type:%s", aInitDataType);
+  // initDataType must be "cenc", "keyids", or "webm".
+  if (aInitDataType != InitDataType::kCenc &&
+      aInitDataType != InitDataType::kKeyIds &&
+      aInitDataType != InitDataType::kWebM) {
 
-  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;
-  }
+    string message = "initDataType is not supported by ClearKey";
+    mHost->OnRejectPromise(aPromiseId,
+                           Error::kNotSupportedError,
+                           0,
+                           message.c_str(),
+                           message.size());
 
-  if (ClearKeyPersistence::DeferCreateSessionIfNotReady(this,
-                                                        aCreateSessionToken,
-                                                        aPromiseId,
-                                                        initDataType,
-                                                        aInitData,
-                                                        aInitDataSize,
-                                                        aSessionType)) {
     return;
   }
 
   string sessionId = ClearKeyPersistence::GetNewSessionId(aSessionType);
   assert(mSessions.find(sessionId) == mSessions.end());
 
-  ClearKeySession* session = new ClearKeySession(sessionId, mCallback, aSessionType);
-  session->Init(aCreateSessionToken, aPromiseId, initDataType, aInitData, aInitDataSize);
+  ClearKeySession* session = new ClearKeySession(sessionId,
+                                                 mHost,
+                                                 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;
+  }
+
   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);
   }
@@ -108,73 +116,96 @@ 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);
-  mCallback->SessionMessage(&sessionId[0], sessionId.length(),
-                            kGMPLicenseRequest,
-                            (uint8_t*)&request[0], request.length());
+
+  //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);
 }
 
 void
 ClearKeySessionManager::LoadSession(uint32_t aPromiseId,
                                     const char* aSessionId,
                                     uint32_t aSessionIdLength)
 {
   CK_LOGD("ClearKeySessionManager::LoadSession");
 
   if (!ClearKeyUtils::IsValidSessionId(aSessionId, aSessionIdLength)) {
-    mCallback->ResolveLoadSessionPromise(aPromiseId, false);
-    return;
-  }
-
-  if (ClearKeyPersistence::DeferLoadSessionIfNotReady(this,
-                                                      aPromiseId,
-                                                      aSessionId,
-                                                      aSessionIdLength)) {
+    mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0);
     return;
   }
 
   string sid(aSessionId, aSessionId + aSessionIdLength);
   if (!ClearKeyPersistence::IsPersistentSessionId(sid)) {
-    mCallback->ResolveLoadSessionPromise(aPromiseId, false);
+    mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0);
     return;
   }
 
-  // Callsback PersistentSessionDataLoaded with results...
-  ClearKeyPersistence::LoadSessionData(this, sid, aPromiseId);
+  function<void(const uint8_t*, uint32_t)> success =
+    [this, sid, aPromiseId]
+  (const uint8_t* data, uint32_t size) -> void {
+    PersistentSessionDataLoaded(FileIOClient::kSuccess,
+                                aPromiseId,
+                                sid,
+                                data,
+                                size);
+  };
+
+  function<void()> failure = [this, sid, aPromiseId]() -> void {
+    // As per the API described in ContentDecryptionModule_8
+    mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0);
+  };
+
+  ReadData(mHost, sid, success, failure);
+
+  mHost->OnResolveNewSessionPromise(aPromiseId, aSessionId, aSessionIdLength);
 }
 
 void
-ClearKeySessionManager::PersistentSessionDataLoaded(GMPErr aStatus,
-                                                    uint32_t aPromiseId,
-                                                    const string& aSessionId,
-                                                    const uint8_t* aKeyData,
-                                                    uint32_t aKeyDataSize)
+ClearKeySessionManager::PersistentSessionDataLoaded(
+  FileIOClient::Status aStatus,
+  uint32_t aPromiseId,
+  const string& aSessionId,
+  const uint8_t* aKeyData,
+  uint32_t aKeyDataSize)
 {
   CK_LOGD("ClearKeySessionManager::PersistentSessionDataLoaded");
-  if (GMP_FAILED(aStatus) ||
+  if (IO_SUCCEEDED(aStatus) ||
       Contains(mSessions, aSessionId) ||
-      (aKeyDataSize % (2 * CENC_KEY_LEN)) != 0) {
-    mCallback->ResolveLoadSessionPromise(aPromiseId, false);
+    (aKeyDataSize % (2 * CENC_KEY_LEN)) != 0) {
+
+    // As per the instructions in ContentDecryptionModule_8
+    mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0);
     return;
   }
 
   ClearKeySession* session = new ClearKeySession(aSessionId,
-                                                 mCallback,
-                                                 kGMPPersistentSession);
+                                                 mHost,
+                                                 SessionType::kPersistentLicense);
+
   mSessions[aSessionId] = session;
 
   uint32_t numKeys = aKeyDataSize / (2 * CENC_KEY_LEN);
 
-  vector<GMPMediaKeyInfo> key_infos;
+  vector<KeyInformation> keyInfos;
   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);
@@ -182,91 +213,137 @@ 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);
 
-    keyPairs.push_back(keyPair);
-    key_infos.push_back(GMPMediaKeyInfo(&keyPairs[i].mKeyId[0],
-                                        keyPairs[i].mKeyId.size(),
-                                        kGMPUsable));
+    KeyInformation keyInfo = KeyInformation();
+    keyInfo.key_id = &keyPair.mKeyId[0];
+    keyInfo.key_id_size = keyPair.mKeyId.size();
+    keyInfo.status = KeyStatus::kUsable;
+
+    keyInfos.push_back(keyInfo);
   }
-  mCallback->BatchedKeyStatusChanged(&aSessionId[0], aSessionId.size(),
-                                     key_infos.data(), key_infos.size());
 
-  mCallback->ResolveLoadSessionPromise(aPromiseId, true);
+  // TODO confirm what the has_additional_usable_keys param should be
+  mHost->OnSessionKeysChange(&aSessionId[0],
+                            aSessionId.size(),
+                            true,
+                            keyInfos.data(),
+                            keyInfos.size());
+
+  mHost->OnResolveNewSessionPromise(aPromiseId,
+                                    aSessionId.c_str(),
+                                    aSessionId.size());
 }
 
 void
 ClearKeySessionManager::UpdateSession(uint32_t aPromiseId,
                                       const char* aSessionId,
                                       uint32_t aSessionIdLength,
                                       const uint8_t* aResponse,
                                       uint32_t aResponseSize)
 {
   CK_LOGD("ClearKeySessionManager::UpdateSession");
   string sessionId(aSessionId, aSessionId + aSessionIdLength);
+  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.");
-    mCallback->RejectPromise(aPromiseId, kGMPNotFoundError, nullptr, 0);
+    CK_LOGD("Unable to find session: %s", sessionId.c_str());
+    mHost->OnRejectPromise(aPromiseId,
+                           Error::kInvalidAccessError,
+                           0,
+                           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.");
-    mCallback->RejectPromise(aPromiseId, kGMPTypeError, nullptr, 0);
+    CK_LOGD("Failed to parse response for session %s", sessionId.c_str());
+
+    mHost->OnRejectPromise(aPromiseId,
+                           Error::kQuotaExceededError,
+                           0,
+                           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.");
-    mCallback->RejectPromise(aPromiseId, kGMPTypeError, nullptr, 0);
+
+    mHost->OnRejectPromise(aPromiseId,
+                           Error::kInvalidStateError,
+                           0,
+                           nullptr,
+                           0);
+
     return;
   }
 
-  vector<GMPMediaKeyInfo> key_infos;
+  vector<KeyInformation> keyInfos;
   for (size_t i = 0; i < keyPairs.size(); i++) {
     KeyIdPair& keyPair = keyPairs[i];
     mDecryptionManager->InitKey(keyPair.mKeyId, keyPair.mKey);
     mKeyIds.insert(keyPair.mKeyId);
-    key_infos.push_back(GMPMediaKeyInfo(&keyPair.mKeyId[0],
-                                        keyPair.mKeyId.size(),
-                                        kGMPUsable));
+
+    KeyInformation keyInfo = KeyInformation();
+    keyInfo.key_id = &keyPair.mKeyId[0];
+    keyInfo.key_id_size = keyPair.mKeyId.size();
+    keyInfo.status = KeyStatus::kUsable;
+
+    keyInfos.push_back(keyInfo);
   }
-  mCallback->BatchedKeyStatusChanged(aSessionId, aSessionIdLength,
-                                     key_infos.data(), key_infos.size());
 
-  if (session->Type() != kGMPPersistentSession) {
-    mCallback->ResolvePromise(aPromiseId);
+  // TODO work out what the 'has_additional_usable_key' param should be set as
+  mHost->OnSessionKeysChange(aSessionId, aSessionIdLength, true,
+    keyInfos.data(), keyInfos.size());
+
+
+  if (session->Type() != SessionType::kPersistentLicense) {
+    mHost->OnResolvePromise(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);
-  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);
+
+  function<void()> resolve = [this, aPromiseId]() -> void {
+    mHost->OnResolvePromise(aPromiseId);
+  };
+
+  function<void()> reject = [this, aPromiseId]() -> void {
+    static const char* message = "Couldn't store cenc key init data";
+    mHost->OnRejectPromise(aPromiseId,
+                           Error::kInvalidStateError,
+                           0,
+                           message,
+                           strlen(message));
+  };
+
+  WriteData(mHost, 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++) {
@@ -288,26 +365,31 @@ ClearKeySessionManager::CloseSession(uin
                                      uint32_t aSessionIdLength)
 {
   CK_LOGD("ClearKeySessionManager::CloseSession");
 
   string sessionId(aSessionId, aSessionId + aSessionIdLength);
   auto itr = mSessions.find(sessionId);
   if (itr == mSessions.end()) {
     CK_LOGW("ClearKey CDM couldn't close non-existent session.");
-    mCallback->RejectPromise(aPromiseId, kGMPNotFoundError, nullptr, 0);
+    mHost->OnRejectPromise(aPromiseId,
+                           Error::kInvalidAccessError,
+                           0,
+                           nullptr,
+                           0);
+
     return;
   }
 
   ClearKeySession* session = itr->second;
   assert(session);
 
   ClearInMemorySessionData(session);
-  mCallback->SessionClosed(aSessionId, aSessionIdLength);
-  mCallback->ResolvePromise(aPromiseId);
+  mHost->OnSessionClosed(aSessionId, aSessionIdLength);
+  mHost->OnResolvePromise(aPromiseId);
 }
 
 void
 ClearKeySessionManager::ClearInMemorySessionData(ClearKeySession* aSession)
 {
   mSessions.erase(aSession->Id());
   delete aSession;
 }
@@ -317,85 +399,100 @@ ClearKeySessionManager::RemoveSession(ui
                                       const char* aSessionId,
                                       uint32_t aSessionIdLength)
 {
   CK_LOGD("ClearKeySessionManager::RemoveSession");
   string sessionId(aSessionId, aSessionId + aSessionIdLength);
   auto itr = mSessions.find(sessionId);
   if (itr == mSessions.end()) {
     CK_LOGW("ClearKey CDM couldn't remove non-existent session.");
-    mCallback->RejectPromise(aPromiseId, kGMPNotFoundError, nullptr, 0);
+
+    mHost->OnRejectPromise(aPromiseId,
+                           Error::kInvalidAccessError,
+                           0,
+                           nullptr,
+                           0);
+
     return;
   }
 
   ClearKeySession* session = itr->second;
   assert(session);
   string sid = session->Id();
-  bool isPersistent = session->Type() == kGMPPersistentSession;
+  bool isPersistent = session->Type() == SessionType::kPersistentLicense;
   ClearInMemorySessionData(session);
 
   if (!isPersistent) {
-    mCallback->ResolvePromise(aPromiseId);
+    mHost->OnResolvePromise(aPromiseId);
     return;
   }
 
   ClearKeyPersistence::PersistentSessionRemoved(sid);
 
-  // Overwrite the record storing the sessionId's key data with a zero
-  // length record to delete it.
+  // TODO Overwrite the record storing the sessionId's key data with a zero
+  // length record to delete it. The API suggests writing null but this
+  // should *hopefully* work. This should be converted to nullptr.
+  // It should also be noted the persistence path is only used in a few tests
+  // and is not enabled in the browser.
   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);
+
+  // TODO double check it's all right to access mHost here...
+  // TODO check that the session key manager hasn't been shutdown before we
+  // resolve the promises
+  function<void()> resolve = [this, aPromiseId, sessionId] () -> void {
+    mHost->OnResolvePromise(aPromiseId);
+  };
+
+  function<void()> reject = [this, aPromiseId, sessionId] () -> void {
+    static const char* message = "Could not remove session";
+    mHost->OnRejectPromise(aPromiseId,
+                           Error::kInvalidAccessError,
+                           0,
+                           message,
+                           strlen(message));
+  };
+
+  WriteData(mHost, 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");
-  mCallback->RejectPromise(aPromiseId, kGMPNotSupportedError,
-                           nullptr /* message */, 0 /* messageLen */);
+  mHost->OnRejectPromise(aPromiseId,
+                         Error::kNotSupportedError,
+                         0,
+                         nullptr /* message */,
+                         0 /* messageLen */);
 }
 
-void
-ClearKeySessionManager::Decrypt(GMPBuffer* aBuffer,
-                                GMPEncryptedBufferMetadata* aMetadata)
+Status
+ClearKeySessionManager::Decrypt(const InputBuffer& aBuffer,
+                                DecryptedBlock* aMetadata)
 {
   CK_LOGD("ClearKeySessionManager::Decrypt");
 
-  if (!mThread) {
-    CK_LOGW("No decrypt thread");
-    mCallback->Decrypted(aBuffer, GMPGenericErr);
-    return;
-  }
+  assert(aBuffer.key_id_size <= 16);
 
-  mThread->Post(WrapTaskRefCounted(this,
-                                   &ClearKeySessionManager::DoDecrypt,
-                                   aBuffer, aMetadata));
-}
+  CK_LOGARRAY("Key: ", aBuffer.key_id, aBuffer.key_id_size);
+
+  Buffer* buffer = mHost->Allocate(aBuffer.data_size);
+  memcpy(buffer->Data(), aBuffer.data, aBuffer.data_size);
 
-void
-ClearKeySessionManager::DoDecrypt(GMPBuffer* aBuffer,
-                                  GMPEncryptedBufferMetadata* aMetadata)
-{
-  CK_LOGD("ClearKeySessionManager::DoDecrypt");
+  Status status = mDecryptionManager->Decrypt(buffer->Data(),
+                                              buffer->Size(),
+                                              CryptoMetaData(&aBuffer));
 
-  GMPErr rv = mDecryptionManager->Decrypt(aBuffer->Data(), aBuffer->Size(),
-                                          CryptoMetaData(aMetadata));
-  CK_LOGD("DeDecrypt finished with code %x\n", rv);
-  mCallback->Decrypted(aBuffer, rv);
+  aMetadata->SetDecryptedBuffer(buffer);
+  aMetadata->SetTimestamp(aBuffer.timestamp);
+
+  return status;
 }
 
 void
 ClearKeySessionManager::Shutdown()
 {
   CK_LOGD("ClearKeySessionManager::Shutdown %p", this);
 
   for (auto it = mSessions.begin(); it != mSessions.end(); it++) {
@@ -404,15 +501,12 @@ ClearKeySessionManager::Shutdown()
   mSessions.clear();
 }
 
 void
 ClearKeySessionManager::DecryptingComplete()
 {
   CK_LOGD("ClearKeySessionManager::DecryptingComplete %p", this);
 
-  GMPThread* thread = mThread;
-  thread->Join();
-
   Shutdown();
   mDecryptionManager = nullptr;
   Release();
 }
--- a/media/gmp-clearkey/0.1/ClearKeySessionManager.h
+++ b/media/gmp-clearkey/0.1/ClearKeySessionManager.h
@@ -1,100 +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.
- */
-
-#ifndef __ClearKeyDecryptor_h__
-#define __ClearKeyDecryptor_h__
-
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "ClearKeyDecryptionManager.h"
-#include "ClearKeySession.h"
-#include "ClearKeyUtils.h"
-#include "gmp-api/gmp-decryption.h"
-#include "RefCounted.h"
-
-class ClearKeySessionManager final : public GMPDecryptor
-                                   , public RefCounted
-{
-public:
-  ClearKeySessionManager();
-
-  virtual void Init(GMPDecryptorCallback* aCallback,
-                    bool aDistinctiveIdentifierAllowed,
-                    bool aPersistentStateAllowed) override;
-
-  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;
-
-  virtual void LoadSession(uint32_t aPromiseId,
-                           const char* aSessionId,
-                           uint32_t aSessionIdLength) override;
-
-  virtual void UpdateSession(uint32_t aPromiseId,
-                             const char* aSessionId,
-                             uint32_t aSessionIdLength,
-                             const uint8_t* aResponse,
-                             uint32_t aResponseSize) override;
-
-  virtual void CloseSession(uint32_t aPromiseId,
-                            const char* aSessionId,
-                            uint32_t aSessionIdLength) override;
-
-  virtual void RemoveSession(uint32_t aPromiseId,
-                             const char* aSessionId,
-                             uint32_t aSessionIdLength) override;
-
-  virtual void SetServerCertificate(uint32_t aPromiseId,
-                                    const uint8_t* aServerCert,
-                                    uint32_t aServerCertSize) override;
-
-  virtual void Decrypt(GMPBuffer* aBuffer,
-                       GMPEncryptedBufferMetadata* aMetadata) override;
-
-  virtual void DecryptingComplete() override;
-
-  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);
-  void Serialize(const ClearKeySession* aSession, std::vector<uint8_t>& aOutKeyData);
-
-  RefPtr<ClearKeyDecryptionManager> mDecryptionManager;
-
-  GMPDecryptorCallback* mCallback;
-  GMPThread* mThread;
-
-  std::set<KeyId> mKeyIds;
-  std::map<std::string, ClearKeySession*> mSessions;
-};
-
-#endif // __ClearKeyDecryptor_h__
+/*
+* 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 "ClearKeyDecryptionManager.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 <map>
+#include <set>
+#include <string>
+#include <vector>
+
+class ClearKeySessionManager final : public RefCounted
+{
+public:
+  ClearKeySessionManager();
+
+  void Init(cdm::Host_8* aHost,
+            bool aDistinctiveIdentifierAllowed,
+            bool aPersistentStateAllowed);
+
+  void CreateSession(uint32_t aPromiseId,
+                     cdm::InitDataType aInitDataType,
+                     const uint8_t* aInitData,
+                     uint32_t aInitDataSize,
+                     cdm::SessionType aSessionType);
+
+  void LoadSession(uint32_t aPromiseId,
+                   const char* aSessionId,
+                   uint32_t aSessionIdLength);
+
+  void UpdateSession(uint32_t aPromiseId,
+                     const char* aSessionId,
+                     uint32_t aSessionIdLength,
+                     const uint8_t* aResponse,
+                     uint32_t aResponseSize);
+
+  void CloseSession(uint32_t aPromiseId,
+                    const char* aSessionId,
+                    uint32_t aSessionIdLength);
+
+  void RemoveSession(uint32_t aPromiseId,
+                     const char* aSessionId,
+                     uint32_t aSessionIdLength);
+
+  void SetServerCertificate(uint32_t aPromiseId,
+                            const uint8_t* aServerCert,
+                            uint32_t aServerCertSize);
+
+  cdm::Status
+  Decrypt(const cdm::InputBuffer& aBuffer, cdm::DecryptedBlock* aMetadata);
+
+  void DecryptingComplete();
+
+  void PersistentSessionDataLoaded(cdm::FileIOClient::Status aStatus,
+                                   uint32_t aPromiseId,
+                                   const std::string& aSessionId,
+                                   const uint8_t* aKeyData,
+                                   uint32_t aKeyDataSize);
+
+private:
+  ~ClearKeySessionManager();
+
+  void Shutdown();
+
+  void ClearInMemorySessionData(ClearKeySession* aSession);
+  void Serialize(const ClearKeySession* aSession,
+                 std::vector<uint8_t>& aOutKeyData);
+
+  RefPtr<ClearKeyDecryptionManager> mDecryptionManager;
+
+  cdm::Host_8* mHost = nullptr;
+
+  std::set<KeyId> mKeyIds;
+  std::map<std::string, ClearKeySession*> mSessions;
+};
+
+#endif // __ClearKeyDecryptor_h__
--- a/media/gmp-clearkey/0.1/ClearKeyStorage.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeyStorage.cpp
@@ -10,185 +10,207 @@
  * 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"
 
-#include "gmp-task-utils.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 <assert.h>
 #include "ArrayUtils.h"
-
 #include <vector>
 
-static GMPErr
-RunOnMainThread(GMPTask* aTask)
-{
-  return GetPlatform()->runonmainthread(aTask);
-}
+using namespace cdm;
+using namespace std;
 
-GMPErr
-OpenRecord(const char* aName,
-           uint32_t aNameLength,
-           GMPRecord** aOutRecord,
-           GMPRecordClient* aClient)
-{
-  return GetPlatform()->createrecord(aName, aNameLength, aOutRecord, aClient);
-}
-
-class WriteRecordClient : public GMPRecordClient {
+class WriteRecordClient : public FileIOClient {
 public:
   /*
    * This function will take the memory ownership of the parameters and
    * delete them when done.
    */
-  static void Write(const std::string& aRecordName,
+  static void Write(Host_8* aHost,
+                    std::string& aRecordName,
                     const std::vector<uint8_t>& aData,
-                    GMPTask* aOnSuccess,
-                    GMPTask* aOnFailure) {
-    (new WriteRecordClient(aData, aOnSuccess, aOnFailure))->Do(aRecordName);
+                    const function<void()>& aOnSuccess,
+                    const function<void()>& aOnFailure) {
+
+    WriteRecordClient* client = new WriteRecordClient(aData,
+                                                      aOnSuccess,
+                                                      aOnFailure);
+    client->Do(aRecordName, aHost);
   }
 
-  virtual void OpenComplete(GMPErr aStatus) override {
-    if (GMP_FAILED(aStatus) ||
-        GMP_FAILED(mRecord->Write(&mData.front(), mData.size()))) {
+  virtual void OnOpenComplete(Status aStatus) override {
+    // If we hit an error, fail
+    if (aStatus != Status::kSuccess) {
       Done(mOnFailure, mOnSuccess);
+    } else if (mFileIO) { // Otherwise, write our data to the file
+      mFileIO->Write(&mData[0], mData.size());
     }
   }
 
-  virtual void ReadComplete(GMPErr aStatus,
-                            const uint8_t* aData,
-                            uint32_t aDataSize) override {
-    assert(false); // Should not reach here.
+  virtual void OnReadComplete(Status aStatus,
+    const uint8_t* aData,
+    uint32_t aDataSize) override {
+    // Should not reach here.
+    assert(false);
   }
 
-  virtual void WriteComplete(GMPErr aStatus) override {
-    if (GMP_FAILED(aStatus)) {
+  virtual void OnWriteComplete(Status aStatus) override {
+    if (aStatus != Status::kSuccess) {
       Done(mOnFailure, mOnSuccess);
-    } else {
+    }
+    else {
       Done(mOnSuccess, mOnFailure);
     }
   }
 
 private:
   WriteRecordClient(const std::vector<uint8_t>& aData,
-                    GMPTask* aOnSuccess,
-                    GMPTask* aOnFailure)
-    : mRecord(nullptr)
+                    const function<void()>& aOnSuccess,
+                    const function<void()>& aOnFailure)
+    : mFileIO(nullptr)
     , mOnSuccess(aOnSuccess)
     , mOnFailure(aOnFailure)
     , mData(aData) {}
 
-  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 Do(const std::string& aName, Host_8* aHost) {
+    // Initialize the FileIO
+    mFileIO = aHost->CreateFileIO(this);
+    mFileIO->Open(aName.c_str(), aName.size());
   }
 
-  void Done(GMPTask* aToRun, GMPTask* aToDestroy) {
+  void Done(const function<void()>& aToRun,
+            const function<void()>& 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 (mRecord) {
-      mRecord->Close();
+    // TODO make sure this doesn't delete the client (see api docs)
+    if (mFileIO) {
+      mFileIO->Close();
     }
-    aToDestroy->Destroy();
-    RunOnMainThread(aToRun);
+
+    // TODO Double check we don't have to be on the main thread.
+    aToRun();
+
     delete this;
   }
 
-  GMPRecord* mRecord;
-  GMPTask* mOnSuccess;
-  GMPTask* mOnFailure;
+  FileIO* mFileIO;
+
+  const function<void()>& mOnSuccess;
+  const function<void()>& mOnFailure;
+
   const std::vector<uint8_t> mData;
 };
 
 void
-StoreData(const std::string& aRecordName,
+WriteData(Host_8* aHost,
+          std::string& aRecordName,
           const std::vector<uint8_t>& aData,
-          GMPTask* aOnSuccess,
-          GMPTask* aOnFailure)
+          const function<void()>& aOnSuccess,
+          const function<void()>& aOnFailure)
 {
-  WriteRecordClient::Write(aRecordName, aData, aOnSuccess, aOnFailure);
+  WriteRecordClient::Write(aHost,
+                           aRecordName,
+                           aData,
+                           aOnSuccess,
+                           aOnFailure);
 }
 
-class ReadRecordClient : public GMPRecordClient {
+class ReadRecordClient : public FileIOClient {
 public:
   /*
    * This function will take the memory ownership of the parameters and
    * delete them when done.
    */
-  static void Read(const std::string& aRecordName,
-                   ReadContinuation* aContinuation) {
-    assert(aContinuation);
-    (new ReadRecordClient(aContinuation))->Do(aRecordName);
+  static void Read(Host_8* aHost,
+                   std::string& aRecordName,
+                   function<void(const uint8_t*, uint32_t)> aOnSuccess,
+                   function<void()> aOnFailure) {
+
+    (new ReadRecordClient(aOnSuccess, aOnFailure))->Do(aRecordName, aHost);
   }
 
-  virtual void OpenComplete(GMPErr aStatus) override {
+  virtual void OnOpenComplete(Status aStatus) override {
     auto err = aStatus;
-    if (GMP_FAILED(err) ||
-        GMP_FAILED(err = mRecord->Read())) {
+    if (aStatus != Status::kSuccess) {
       Done(err, nullptr, 0);
     }
+    else {
+      mFileIO->Read();
+    }
   }
 
-  virtual void ReadComplete(GMPErr aStatus,
-                            const uint8_t* aData,
-                            uint32_t aDataSize) override {
+  virtual void OnReadComplete(Status aStatus,
+                              const uint8_t* aData,
+                              uint32_t aDataSize) override {
     Done(aStatus, aData, aDataSize);
   }
 
-  virtual void WriteComplete(GMPErr aStatus) override {
+  virtual void OnWriteComplete(Status aStatus) override {
     assert(false); // Should not reach here.
   }
 
 private:
-  explicit ReadRecordClient(ReadContinuation* aContinuation)
-    : mRecord(nullptr)
-    , mContinuation(aContinuation) {}
+  explicit ReadRecordClient(function<void(const uint8_t*, uint32_t)> aOnSuccess,
+                            function<void()> aOnFailure)
+    : mOnSuccess(aOnSuccess),
+      mOnFailure(aOnFailure)
+  {}
 
-  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 Do(const std::string& aName, Host_8* aHost) {
+    mFileIO = aHost->CreateFileIO(this);
+    mFileIO->Open(aName.c_str(), aName.size());
   }
 
-  void Done(GMPErr err, const uint8_t* aData, uint32_t aDataSize) {
+  void Done(cdm::FileIOClient::Status 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 (mRecord) {
-      mRecord->Close();
+    if (mFileIO) {
+      mFileIO->Close();
     }
-    mContinuation->ReadComplete(err, aData, aDataSize);
-    delete mContinuation;
+
+    if (IO_SUCCEEDED(err)) {
+      mOnSuccess(aData, aDataSize);
+    }
+    else {
+      mOnFailure();
+    }
+
     delete this;
   }
 
-  GMPRecord* mRecord;
-  ReadContinuation* mContinuation;
+  function<void(const uint8_t*, uint32_t)> mOnSuccess;
+  function<void()> mOnFailure;
+
+  FileIO* mFileIO;
 };
 
-void
-ReadData(const std::string& aRecordName,
-         ReadContinuation* aContinuation)
-{
-  ReadRecordClient::Read(aRecordName, aContinuation);
+void ReadData(Host_8* mHost,
+              std::string& aRecordName,
+              const function<void(const uint8_t*, uint32_t)>& aOnSuccess,
+              const function<void()>& aOnFailure) {
+  ReadRecordClient::Read(mHost, aRecordName, aOnSuccess, aOnFailure);
 }
 
 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
@@ -14,35 +14,37 @@
  * limitations under the License.
  */
 
 #ifndef __ClearKeyStorage_h__
 #define __ClearKeyStorage_h__
 
 #include "gmp-api/gmp-errors.h"
 #include "gmp-api/gmp-platform.h"
+
+#include <functional>
+#include <stdint.h>
 #include <string>
 #include <vector>
-#include <stdint.h>
+
+#include "ClearKeySessionManager.h"
+
+#define IO_SUCCEEDED(x) ((x) == cdm::FileIOClient::Status::kSuccess)
+#define IO_FAILED(x) ((x) != cdm::FileIOClient::Status::kSuccess)
 
 class GMPTask;
 
-// Responsible for ensuring that both aOnSuccess and aOnFailure are destroyed.
-void StoreData(const std::string& aRecordName,
+// 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,
-               GMPTask* aOnSuccess,
-               GMPTask* aOnFailure);
+               const std::function<void()>& aOnSuccess,
+               const std::function<void()>& aOnFailure);
 
-class ReadContinuation {
-public:
-  virtual void ReadComplete(GMPErr aStatus,
-                            const uint8_t* aData,
-                            uint32_t aLength) = 0;
-  virtual ~ReadContinuation() {}
-};
-
-// Deletes aContinuation after running it to report the result.
-void ReadData(const std::string& aSessionId,
-              ReadContinuation* aContinuation);
+// Reads data from a file and fires the appropriate callback when complete
+void ReadData(cdm::Host_8* aHost,
+              std::string& aRecordName,
+              const std::function<void(const uint8_t*, uint32_t)>& aOnSuccess,
+              const std::function<void()>& aOnFailure);
 
 GMPErr EnumRecordNames(RecvGMPRecordIteratorPtr aRecvIteratorFunc);
 
 #endif // __ClearKeyStorage_h__
--- a/media/gmp-clearkey/0.1/ClearKeyUtils.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeyUtils.cpp
@@ -9,43 +9,83 @@
  *
  * 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 <ctype.h>
+#include <memory.h>
 #include <stdarg.h>
 #include <stdint.h>
 #include <vector>
 
-#include "ClearKeyUtils.h"
+#include "ArrayUtils.h"
+#include "BigEndian.h"
 #include "ClearKeyBase64.h"
-#include "ArrayUtils.h"
-#include <assert.h>
-#include <memory.h>
-#include "BigEndian.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 "openaes/oaes_lib.h"
+#include "psshparser/PsshParser.h"
 
+using namespace cdm;
 using namespace std;
 
 void
 CK_Log(const char* aFmt, ...)
 {
+  FILE* out = stdout;
+  bool usingFile = false;
+
+  if (getenv("CLEARKEY_LOG_FILE")) {
+    out = fopen(getenv("CLEARKEY_LOG_FILE"), "a");
+    usingFile = true;
+  }
+
   va_list ap;
 
   va_start(ap, aFmt);
-  vprintf(aFmt, ap);
+  const size_t len = 1024;
+  char buf[len];
+  vsnprintf(buf, len, aFmt, ap);
   va_end(ap);
 
-  printf("\n");
-  fflush(stdout);
+  fprintf(out, "%s\n", buf);
+  fflush(out);
+
+  if (usingFile) {
+    fclose(out);
+  }
+
+  out = nullptr;
+}
+
+void CK_LogArray(const char* prepend,
+                 const uint8_t* aData,
+                 const uint32_t aDataSize) {
+  const size_t bufferSize = 1024;
+  size_t remain = bufferSize;
+  char buffer[bufferSize] = { 0 };
+  char* start = &buffer[0];
+
+  for (uint32_t i = 0; i < aDataSize; ++i) {
+    uint32_t wrote = snprintf(start, remain, "%hhX", aData[i]);
+    remain -= wrote;
+    start += wrote;
+  }
+
+  CK_Log("%s%s", prepend, buffer);
 }
 
 static void
 IncrementIV(vector<uint8_t>& aIV) {
   using mozilla::BigEndian;
 
   assert(aIV.size() == 16);
   BigEndian::writeUint64(&aIV[8], BigEndian::readUint64(&aIV[8]) + 1);
@@ -110,27 +150,29 @@ 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]);
-    assert(idx < MOZ_ARRAY_LENGTH(sAlphabet)); // out of bounds index for 'sAlphabet'
+
+    // out of bounds index for 'sAlphabet'
+    assert(idx < MOZ_ARRAY_LENGTH(sAlphabet));
     out[i] = sAlphabet[idx];
   }
 
   return true;
 }
 
 /* static */ void
 ClearKeyUtils::MakeKeyRequest(const vector<KeyId>& aKeyIDs,
                               string& aOutRequest,
-                              GMPSessionType aSessionType)
+                              SessionType aSessionType)
 {
   assert(aKeyIDs.size() && aOutRequest.empty());
 
   aOutRequest.append("{\"kids\":[");
   for (size_t i = 0; i < aKeyIDs.size(); i++) {
     if (i) {
       aOutRequest.append(",");
     }
@@ -384,17 +426,17 @@ ParseKeys(ParserContext& aCtx, vector<Ke
   }
 
   return GetNextSymbol(aCtx) == ']';
 }
 
 /* static */ bool
 ClearKeyUtils::ParseJWK(const uint8_t* aKeyData, uint32_t aKeyDataSize,
                         vector<KeyIdPair>& aOutKeys,
-                        GMPSessionType aSessionType)
+                        SessionType aSessionType)
 {
   ParserContext ctx;
   ctx.mIter = aKeyData;
   ctx.mEnd = aKeyData + aKeyDataSize;
 
   // Consume '{' from start of object.
   EXPECT_SYMBOL(ctx, '{');
 
@@ -500,25 +542,25 @@ ClearKeyUtils::ParseKeyIdsInitData(const
 
   // Consume '}' from end of object.
   EXPECT_SYMBOL(ctx, '}');
 
   return true;
 }
 
 /* static */ const char*
-ClearKeyUtils::SessionTypeToString(GMPSessionType aSessionType)
+ClearKeyUtils::SessionTypeToString(SessionType aSessionType)
 {
   switch (aSessionType) {
-    case kGMPTemporySession: return "temporary";
-    case kGMPPersistentSession: return "persistent-license";
-    default: {
-      assert(false); // Should not reach here.
-      return "invalid";
-    }
+  case SessionType::kTemporary: return "temporary";
+  case SessionType::kPersistentLicense: 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
@@ -527,15 +569,8 @@ ClearKeyUtils::IsValidSessionId(const ch
   }
   for (uint32_t i = 0; i < aLength; i++) {
     if (!isdigit(aBuff[i])) {
       return false;
     }
   }
   return true;
 }
-
-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,43 +16,57 @@
 
 #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
 #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
 {
@@ -61,22 +75,22 @@ 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,
-                             GMPSessionType aSessionType);
+                             cdm::SessionType aSessionType);
 
   static bool ParseJWK(const uint8_t* aKeyData, uint32_t aKeyDataSize,
                        std::vector<KeyIdPair>& aOutKeys,
-                       GMPSessionType aSessionType);
-  static const char* SessionTypeToString(GMPSessionType aSessionType);
+                       cdm::SessionType aSessionType);
+  static const char* SessionTypeToString(cdm::SessionType aSessionType);
 
   static bool IsValidSessionId(const char* aBuff, uint32_t aLength);
 };
 
 template<class Container, class Element>
 inline bool
 Contains(const Container& aContainer, const Element& aElement)
 {
--- a/media/gmp-clearkey/0.1/RefCounted.h
+++ b/media/gmp-clearkey/0.1/RefCounted.h
@@ -83,34 +83,48 @@ protected:
   }
   AtomicRefCount mRefCount;
 };
 
 template<class T>
 class RefPtr {
 public:
   explicit RefPtr(T* aPtr) : mPtr(nullptr) {
-    Assign(aPtr);
+    Set(aPtr);
   }
+  RefPtr() { Set(nullptr); }
+
   ~RefPtr() {
-    Assign(nullptr);
+    Set(nullptr);
   }
   T* operator->() const { return mPtr; }
+  T** operator&() { return &mPtr; }
+  T* operator->() { return mPtr; }
+  operator T*() { return mPtr; }
+  T* operator=(T* const & aPtr) { return Set(aPtr); }
+  T* operator=(const std::nullptr_t& aPtr) { return mPtr = aPtr; }
+
+  T* Get() const { return mPtr; }
 
   RefPtr& operator=(T* aVal) {
-    Assign(aVal);
+    Set(aVal);
     return *this;
   }
 
 private:
-  void Assign(T* aPtr) {
+  T* Set(T* aPtr) {
+    if (mPtr == aPtr) {
+      return aPtr;
+    }
     if (mPtr) {
       mPtr->Release();
     }
     mPtr = aPtr;
     if (mPtr) {
       aPtr->AddRef();
     }
+    return mPtr;
   }
+
   T* mPtr;
 };
 
 #endif // __RefCount_h__
--- a/media/gmp-clearkey/0.1/VideoDecoder.cpp
+++ b/media/gmp-clearkey/0.1/VideoDecoder.cpp
@@ -12,444 +12,323 @@
  * 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 <cstdint>
 #include <limits>
 
-#include "AnnexB.h"
 #include "BigEndian.h"
 #include "ClearKeyDecryptionManager.h"
 #include "ClearKeyUtils.h"
-#include "gmp-task-utils.h"
+#include "unicode\std_string.h"
 #include "VideoDecoder.h"
 
 using namespace wmf;
+using namespace cdm;
 
-VideoDecoder::VideoDecoder(GMPVideoHost *aHostAPI)
-  : mHostAPI(aHostAPI)
-  , mCallback(nullptr)
-  , mWorkerThread(nullptr)
-  , mMutex(nullptr)
-  , mNumInputTasks(0)
-  , mSentExtraData(false)
-  , mIsFlushing(false)
+VideoDecoder::VideoDecoder(Host_8 *aHost)
+  : mHost(aHost)
   , mHasShutdown(false)
 {
   // We drop the ref in DecodingComplete().
   AddRef();
+
+  mDecoder = new WMFH264Decoder();
+
+  uint32_t cores = std::thread::hardware_concurrency();
+
+  // If the method is unable to determine the number of cores it returns zero
+  if (cores == 0) {
+	  cores = 1;
+  }
+
+  HRESULT hr = mDecoder->Init(cores);
 }
 
 VideoDecoder::~VideoDecoder()
 {
-  if (mMutex) {
-    mMutex->Destroy();
-  }
+
 }
 
-void
-VideoDecoder::InitDecode(const GMPVideoCodec& aCodecSettings,
-                         const uint8_t* aCodecSpecific,
-                         uint32_t aCodecSpecificLength,
-                         GMPVideoDecoderCallback* aCallback,
-                         int32_t aCoreCount)
+Status
+VideoDecoder::InitDecode(const VideoDecoderConfig& aConfig)
 {
-  mCallback = aCallback;
-  assert(mCallback);
-  mDecoder = new WMFH264Decoder();
-  HRESULT hr = mDecoder->Init(aCoreCount);
-  if (FAILED(hr)) {
+  if (!mDecoder) {
     CK_LOGD("VideoDecoder::InitDecode failed to init WMFH264Decoder");
-    mCallback->Error(GMPGenericErr);
-    return;
-  }
 
-  auto err = GetPlatform()->createmutex(&mMutex);
-  if (GMP_FAILED(err)) {
-    CK_LOGD("VideoDecoder::InitDecode failed to create GMPMutex");
-    mCallback->Error(GMPGenericErr);
-    return;
+    return Status::kDecodeError;
   }
 
-  // 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);
+  return Status::kSuccess;
 }
 
-void
-VideoDecoder::EnsureWorker()
+Status
+VideoDecoder::Decode(const InputBuffer& aInputBuffer, VideoFrame* 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;
+  // If the input buffer we have been passed has a null buffer, it means we
+  // should drain
+  if (aInputBuffer.data == nullptr) {
+    // 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);
   }
 
-  EnsureWorker();
+  DecodeData* data = new DecodeData();
+  Assign(data->mBuffer, aInputBuffer.data, aInputBuffer.data_size);
+  data->mTimestamp = aInputBuffer.timestamp;
+  data->mCrypto = CryptoMetaData(&aInputBuffer);
 
-  {
-    AutoLock lock(mMutex);
-    mNumInputTasks++;
+  CK_LOGD("VideoDecoder::DecodeTask");
+  AutoPtr<DecodeData> d(data);
+  HRESULT hr;
+
+  if (!data || !mDecoder) {
+    CK_LOGE("Decode job not set up correctly!");
+    return Status::kDecodeError;
   }
 
-  // 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, 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));
-}
+  std::vector<uint8_t>& buffer = data->mBuffer;
 
-void
-VideoDecoder::DecodeTask(DecodeData* aData)
-{
-  CK_LOGD("VideoDecoder::DecodeTask");
-  AutoPtr<DecodeData> d(aData);
-  HRESULT hr;
-
-  {
-    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;
-  }
-
-  std::vector<uint8_t>& buffer = aData->mBuffer;
-  if (aData->mCrypto.IsValid()) {
+  if (data->mCrypto.IsValid()) {
     // Plugin host should have set up its decryptor/key sessions
     // before trying to decode!
-    GMPErr rv =
-      ClearKeyDecryptionManager::Get()->Decrypt(buffer, aData->mCrypto);
+
+    // This decrypts the data in place
+
+    Status rv =
+      ClearKeyDecryptionManager::Get()->Decrypt(buffer, data->mCrypto);
 
-    if (GMP_FAILED(rv)) {
-      MaybeRunOnMainThread(WrapTask(mCallback, &GMPVideoDecoderCallback::Error, rv));
-      return;
+    if (STATUS_FAILED(rv)) {
+      CK_LOGARRAY("Failed to decrypt video using key ",
+                  aInputBuffer.key_id,
+                  aInputBuffer.key_id_size);
+      return rv;
     }
   }
 
-  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(),
-                       aData->mTimestamp,
-                       aData->mDuration);
+                       data->mTimestamp);
 
   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)" : ""));
-    return;
+      hr,
+      ((hr == MF_E_NOTACCEPTING) ? " (MF_E_NOTACCEPTING)" : ""));
+    CK_LOGD("Decode failed. The decoder is not accepting input");
+    return Status::kDecodeError;
   }
 
-  while (hr == S_OK) {
+  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) {
     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()));
-    }
-    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;
-
-  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;
+  // 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;
   }
 
-  auto vf = static_cast<GMPVideoi420Frame*>(f);
+  // We will get a MF_E_TRANSFORM_NEED_MORE_INPUT every time, as we read
+  // 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();
 
-  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;
+  }
 
-  mCallback->Decoded(vf);
+  mOutputQueue.pop();
+
+  CK_LOGD("Decode succeeded.");
+  return Status::kSuccess;
 }
 
 HRESULT
 VideoDecoder::SampleToVideoFrame(IMFSample* aSample,
                                  int32_t aWidth,
                                  int32_t aHeight,
                                  int32_t aStride,
-                                 GMPVideoi420Frame* aVideoFrame)
+                                 VideoFrame* aVideoFrame)
 {
+  CK_LOGD("[%p] VideoDecoder::SampleToVideoFrame()\n", this);
+  assert(aSample);
+
+  // WideVine doesn't have support for negative strides
+  assert(aStride > 0);
+
   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, NULL, NULL);
+    hr = mediaBuffer->Lock(&data, nullptr, nullptr);
     ENSURE(SUCCEEDED(hr), hr);
     stride = aStride;
   }
 
   // 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....][VVVV....][UUUU....]
   // i.e., Y, then V, then U.
   uint32_t padding = 0;
   if (aHeight % 16 != 0) {
     padding = 16 - (aHeight % 16);
   }
-  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;
+  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;
+
+  uint32_t uOffset = stride*aHeight;
+  uint32_t vOffset = stride*aHeight + halfStride*halfHeight;
 
-  auto err = aVideoFrame->CreateEmptyFrame(stride, aHeight, stride, halfStride, halfStride);
-  ENSURE(GMP_SUCCEEDED(err), E_FAIL);
+  aVideoFrame->SetStride(VideoFrame::kYPlane, stride);
+  aVideoFrame->SetStride(VideoFrame::kUPlane, halfStride);
+  aVideoFrame->SetStride(VideoFrame::kVPlane, halfStride);
+
+  aVideoFrame->SetSize(Size(aWidth, aHeight));
+
+  uint64_t bufferSize = static_cast<uint64_t>(stride)
+                        * aHeight
+                        + 2* halfStride*halfHeight;
 
-  err = aVideoFrame->SetWidth(aWidth);
-  ENSURE(GMP_SUCCEEDED(err), E_FAIL);
-  err = aVideoFrame->SetHeight(aHeight);
-  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;
+  }
+
+  // Get the buffer from the host
+  Buffer* buffer = mHost->Allocate(bufferSize);
+  aVideoFrame->SetFrameBuffer(buffer);
 
-  uint8_t* outBuffer = aVideoFrame->Buffer(kGMPYPlane);
-  ENSURE(outBuffer != nullptr, E_FAIL);
-  assert(aVideoFrame->AllocatedSize(kGMPYPlane) >= stride*aHeight);
+  // Make sure it gave us what we want
+  assert(buffer != nullptr);
+  assert(buffer->Capacity() >= bufferSize);
+
+  uint8_t* outBuffer = buffer->Data();
+
+  assert(outBuffer != nullptr);
+  assert(buffer->Capacity() >= bufferSize);
+
+  aVideoFrame->SetPlaneOffset(VideoFrame::kYPlane, 0);
+  // Copy the y data
   memcpy(outBuffer, data, stride*aHeight);
 
-  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, uOffset);
+  // Copy the v data.
+  memcpy(outBuffer + uOffset, data + ySize, halfStride*halfHeight);
 
-  outBuffer = aVideoFrame->Buffer(kGMPVPlane);
-  ENSURE(outBuffer != nullptr, E_FAIL);
-  assert(aVideoFrame->AllocatedSize(kGMPVPlane) >= halfStride*halfHeight);
-  memcpy(outBuffer, data + y_size + v_size, halfStride*halfHeight);
+  // Offset is the size of the copied y_data + the size of the copied u_data
+  aVideoFrame->SetPlaneOffset(VideoFrame::kVPlane, vOffset);
+  // Copy the v data.
+  memcpy(outBuffer + vOffset, data + ySize + uSize, 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()
 {
-  mIsFlushing = true;
+  CK_LOGD("VideoDecoder::Reset");
+
   if (mDecoder) {
     mDecoder->Reset();
   }
 
-  // Schedule ResetComplete callback to run after existing frames have been
-  // flushed out of the task queue.
-  EnsureWorker();
-  mWorkerThread->Post(WrapTaskRefCounted(this,
-                                         &VideoDecoder::ResetCompleteTask));
+  // Remove all the frames from the output queue
+  while (mOutputQueue.size() > 0) {
+    mOutputQueue.pop();
+  }
 }
 
-void
-VideoDecoder::DrainTask()
+Status
+VideoDecoder::Drain(VideoFrame* aVideoFrame)
 {
+  CK_LOGD("VideoDecoder::Drain()");
+
+  if (!mDecoder) {
+    CK_LOGD("Drain failed! Decoder was not initialized");
+    return Status::kDecodeError;
+  }
+
   mDecoder->Drain();
 
   // Return any pending output.
-  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));
+  return OutputFrame(aVideoFrame);
 }
 
 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,98 +13,67 @@
  * 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>
 
-#include "gmp-task-utils.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-video-decode.h"
 #include "gmp-video-host.h"
 #include "WMFH264Decoder.h"
 
-#include "mfobjects.h"
-
-class VideoDecoder : public GMPVideoDecoder
-                   , public RefCounted
+class VideoDecoder : public RefCounted
 {
 public:
-  VideoDecoder(GMPVideoHost *aHostAPI);
+  VideoDecoder(cdm::Host_8 *aHost);
 
-  virtual void InitDecode(const GMPVideoCodec& aCodecSettings,
-                          const uint8_t* aCodecSpecific,
-                          uint32_t aCodecSpecificLength,
-                          GMPVideoDecoderCallback* aCallback,
-                          int32_t aCoreCount) override;
+  cdm::Status InitDecode(const cdm::VideoDecoderConfig& aConfig);
 
-  virtual void Decode(GMPVideoEncodedFrame* aInputFrame,
-                      bool aMissingFrames,
-                      const uint8_t* aCodecSpecific,
-                      uint32_t aCodecSpecificLength,
-                      int64_t aRenderTimeMs = -1);
+  cdm::Status Decode(const cdm::InputBuffer& aEncryptedBuffer,
+    cdm::VideoFrame* aVideoFrame);
 
-  virtual void Reset() override;
+  void Reset();
 
-  virtual void Drain() override;
-
-  virtual void DecodingComplete() override;
+  void DecodingComplete();
 
   bool HasShutdown() { return mHasShutdown; }
 
 private:
 
   virtual ~VideoDecoder();
 
-  void EnsureWorker();
-
-  void DrainTask();
+  cdm::Status Drain(cdm::VideoFrame* aVideoFrame);
 
   struct DecodeData {
     DecodeData()
       : mTimestamp(0)
-      , mDuration(0)
-      , mIsKeyframe(false)
     {}
     std::vector<uint8_t> mBuffer;
     uint64_t mTimestamp;
-    uint64_t mDuration;
-    bool mIsKeyframe;
     CryptoMetaData mCrypto;
   };
 
-  void DecodeTask(DecodeData* aData);
-
-  void ResetCompleteTask();
-
-  void ReturnOutput(IMFSample* aSample,
-                    int32_t aWidth,
-                    int32_t aHeight,
-                    int32_t aStride);
+  cdm::Status OutputFrame(cdm::VideoFrame* aVideoFrame);
 
   HRESULT SampleToVideoFrame(IMFSample* aSample,
                              int32_t aWidth,
                              int32_t aHeight,
                              int32_t aStride,
-                             GMPVideoi420Frame* aVideoFrame);
-
-  void MaybeRunOnMainThread(GMPTask* aTask);
+                             cdm::VideoFrame* aVideoFrame);
 
-  GMPVideoHost *mHostAPI; // host-owned, invalid at DecodingComplete
-  GMPVideoDecoderCallback* mCallback; // host-owned, invalid at DecodingComplete
-  GMPThread* mWorkerThread;
-  GMPMutex* mMutex;
-  wmf::AutoPtr<wmf::WMFH264Decoder> mDecoder;
+  cdm::Host_8* mHost;
+  wmf::AutoPtr<wmf::WMFH264Decoder> mDecoder = nullptr;
 
-  std::vector<uint8_t> mExtraData;
-  std::vector<uint8_t> mAnnexB;
-
-  int32_t mNumInputTasks;
-  bool mSentExtraData;
-
-  std::atomic<bool> mIsFlushing;
+  std::queue<wmf::CComPtr<IMFSample>> mOutputQueue;
 
   bool mHasShutdown;
 };
 
 #endif // __VideoDecoder_h__
--- a/media/gmp-clearkey/0.1/WMFH264Decoder.cpp
+++ b/media/gmp-clearkey/0.1/WMFH264Decoder.cpp
@@ -191,17 +191,16 @@ 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;
@@ -226,18 +225,16 @@ 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)
 {
@@ -296,22 +293,21 @@ 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 aDuration)
+                      Microseconds aTimestamp)
 {
   HRESULT hr;
   CComPtr<IMFSample> input = nullptr;
-  hr = CreateInputSample(aData, aDataSize, aTimestamp, aDuration, &input);
+  hr = CreateInputSample(aData, aDataSize, aTimestamp, &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,18 +25,17 @@ class WMFH264Decoder {
 public:
   WMFH264Decoder();
   ~WMFH264Decoder();
 
   HRESULT Init(int32_t aCoreCount);
 
   HRESULT Input(const uint8_t* aData,
                 uint32_t aDataSize,
-                Microseconds aTimestamp,
-                Microseconds aDuration);
+                Microseconds aTimestamp);
 
   HRESULT Output(IMFSample** aOutput);
 
   HRESULT Reset();
 
   int32_t GetFrameWidth() const;
   int32_t GetFrameHeight() const;
   const IntRect& GetPictureRegion() const;
@@ -48,17 +47,16 @@ 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 GMP_SUCCEEDED(x) ((x) == GMPNoErr)
-#define GMP_FAILED(x) ((x) != GMPNoErr)
+#define STATUS_SUCCEEDED(x) ((x) == Status::kSuccess)
+#define STATUS_FAILED(x) ((x) != Status::kSuccess)
 
 #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,73 +13,63 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
-#include "ClearKeyAsyncShutdown.h"
+#include "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"
 #include "gmp-api/gmp-async-shutdown.h"
 #include "gmp-api/gmp-decryption.h"
 #include "gmp-api/gmp-platform.h"
 
-#if defined(ENABLE_WMF)
+#ifdef ENABLE_WMF
 #include "WMFUtils.h"
-#include "VideoDecoder.h"
-#endif
+#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" {
 
-GMP_EXPORT GMPErr
-GMPInit(GMPPlatformAPI* aPlatformAPI)
-{
-  sPlatform = aPlatformAPI;
-  return GMPNoErr;
-}
-
-GMP_EXPORT GMPErr
-GMPGetAPI(const char* aApiName, void* aHostAPI, void** aPluginAPI)
-{
-  CK_LOGD("ClearKey GMPGetAPI |%s|", aApiName);
-  assert(!*aPluginAPI);
+  CDM_EXPORT
+    void INITIALIZE_CDM_MODULE() {
 
-  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);
   }
 
-  return *aPluginAPI ? GMPNoErr : GMPNotImplementedErr;
-}
+  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) {
+
+    CK_LOGE("ClearKey CreateCDMInstance");
 
-GMP_EXPORT GMPErr
-GMPShutdown(void)
-{
-  CK_LOGD("ClearKey GMPShutdown");
-  return GMPNoErr;
-}
+#ifdef ENABLE_WMF
+    if (!wmf::EnsureLibs()) {
+      CK_LOGE("Required libraries were not found");
+      return nullptr;
+    }
+#endif
+
+    cdm::Host_8* host = static_cast<cdm::Host_8*>(
+      get_cdm_host_func(cdm_interface_version, user_data));
+    ClearKeyCDM* clearKey = new ClearKeyCDM(host);
+
+    CK_LOGE("Created ClearKeyCDM instance!");
+
+    return clearKey;
+  }
 
 }
deleted file mode 100644
--- a/media/gmp-clearkey/0.1/gmp-task-utils-generated.h
+++ /dev/null
@@ -1,1938 +0,0 @@
-/*
- * 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);
-}
deleted file mode 100644
--- a/media/gmp-clearkey/0.1/gmp-task-utils.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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,48 +6,50 @@
 
 SharedLibrary('clearkey')
 
 FINAL_TARGET = 'dist/bin/gmp-clearkey/0.1'
 
 FINAL_TARGET_PP_FILES += ['clearkey.info.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',
 ]