summaryrefslogtreecommitdiffstats
path: root/dom/media/gmp/GMPDecryptorChild.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/gmp/GMPDecryptorChild.cpp')
-rw-r--r--dom/media/gmp/GMPDecryptorChild.cpp403
1 files changed, 403 insertions, 0 deletions
diff --git a/dom/media/gmp/GMPDecryptorChild.cpp b/dom/media/gmp/GMPDecryptorChild.cpp
new file mode 100644
index 000000000..6da3c6c43
--- /dev/null
+++ b/dom/media/gmp/GMPDecryptorChild.cpp
@@ -0,0 +1,403 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GMPDecryptorChild.h"
+#include "GMPContentChild.h"
+#include "GMPChild.h"
+#include "base/task.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/Unused.h"
+#include "runnable_utils.h"
+#include <ctime>
+
+#define ON_GMP_THREAD() (mPlugin->GMPMessageLoop() == MessageLoop::current())
+
+#define CALL_ON_GMP_THREAD(_func, ...) \
+ CallOnGMPThread(&GMPDecryptorChild::_func, __VA_ARGS__)
+
+namespace mozilla {
+namespace gmp {
+
+GMPDecryptorChild::GMPDecryptorChild(GMPContentChild* aPlugin,
+ const nsTArray<uint8_t>& aPluginVoucher,
+ const nsTArray<uint8_t>& aSandboxVoucher)
+ : mSession(nullptr)
+ , mPlugin(aPlugin)
+ , mPluginVoucher(aPluginVoucher)
+ , mSandboxVoucher(aSandboxVoucher)
+{
+ MOZ_ASSERT(mPlugin);
+}
+
+GMPDecryptorChild::~GMPDecryptorChild()
+{
+}
+
+template <typename MethodType, typename... ParamType>
+void
+GMPDecryptorChild::CallMethod(MethodType aMethod, ParamType&&... aParams)
+{
+ MOZ_ASSERT(ON_GMP_THREAD());
+ // Don't send IPC messages after tear-down.
+ if (mSession) {
+ (this->*aMethod)(Forward<ParamType>(aParams)...);
+ }
+}
+
+template<typename T>
+struct AddConstReference {
+ typedef const typename RemoveReference<T>::Type& Type;
+};
+
+template<typename MethodType, typename... ParamType>
+void
+GMPDecryptorChild::CallOnGMPThread(MethodType aMethod, ParamType&&... aParams)
+{
+ if (ON_GMP_THREAD()) {
+ // Use forwarding reference when we can.
+ CallMethod(aMethod, Forward<ParamType>(aParams)...);
+ } else {
+ // Use const reference when we have to.
+ auto m = &GMPDecryptorChild::CallMethod<
+ decltype(aMethod), typename AddConstReference<ParamType>::Type...>;
+ RefPtr<mozilla::Runnable> t =
+ dont_add_new_uses_of_this::NewRunnableMethod(this, m, aMethod, Forward<ParamType>(aParams)...);
+ mPlugin->GMPMessageLoop()->PostTask(t.forget());
+ }
+}
+
+void
+GMPDecryptorChild::Init(GMPDecryptor* aSession)
+{
+ MOZ_ASSERT(aSession);
+ mSession = aSession;
+ // The ID of this decryptor is the IPDL actor ID. Note it's unique inside
+ // the child process, but not necessarily across all gecko processes. However,
+ // since GMPDecryptors are segregated by node ID/origin, we shouldn't end up
+ // with clashes in the content process.
+ SendSetDecryptorId(Id());
+}
+
+void
+GMPDecryptorChild::SetSessionId(uint32_t aCreateSessionToken,
+ const char* aSessionId,
+ uint32_t aSessionIdLength)
+{
+ CALL_ON_GMP_THREAD(SendSetSessionId,
+ aCreateSessionToken, nsCString(aSessionId, aSessionIdLength));
+}
+
+void
+GMPDecryptorChild::ResolveLoadSessionPromise(uint32_t aPromiseId,
+ bool aSuccess)
+{
+ CALL_ON_GMP_THREAD(SendResolveLoadSessionPromise, aPromiseId, aSuccess);
+}
+
+void
+GMPDecryptorChild::ResolvePromise(uint32_t aPromiseId)
+{
+ CALL_ON_GMP_THREAD(SendResolvePromise, aPromiseId);
+}
+
+void
+GMPDecryptorChild::RejectPromise(uint32_t aPromiseId,
+ GMPDOMException aException,
+ const char* aMessage,
+ uint32_t aMessageLength)
+{
+ CALL_ON_GMP_THREAD(SendRejectPromise,
+ aPromiseId, aException, nsCString(aMessage, aMessageLength));
+}
+
+void
+GMPDecryptorChild::SessionMessage(const char* aSessionId,
+ uint32_t aSessionIdLength,
+ GMPSessionMessageType aMessageType,
+ const uint8_t* aMessage,
+ uint32_t aMessageLength)
+{
+ nsTArray<uint8_t> msg;
+ msg.AppendElements(aMessage, aMessageLength);
+ CALL_ON_GMP_THREAD(SendSessionMessage,
+ nsCString(aSessionId, aSessionIdLength),
+ aMessageType, Move(msg));
+}
+
+void
+GMPDecryptorChild::ExpirationChange(const char* aSessionId,
+ uint32_t aSessionIdLength,
+ GMPTimestamp aExpiryTime)
+{
+ CALL_ON_GMP_THREAD(SendExpirationChange,
+ nsCString(aSessionId, aSessionIdLength), aExpiryTime);
+}
+
+void
+GMPDecryptorChild::SessionClosed(const char* aSessionId,
+ uint32_t aSessionIdLength)
+{
+ CALL_ON_GMP_THREAD(SendSessionClosed,
+ nsCString(aSessionId, aSessionIdLength));
+}
+
+void
+GMPDecryptorChild::SessionError(const char* aSessionId,
+ uint32_t aSessionIdLength,
+ GMPDOMException aException,
+ uint32_t aSystemCode,
+ const char* aMessage,
+ uint32_t aMessageLength)
+{
+ CALL_ON_GMP_THREAD(SendSessionError,
+ nsCString(aSessionId, aSessionIdLength),
+ aException, aSystemCode,
+ nsCString(aMessage, aMessageLength));
+}
+
+void
+GMPDecryptorChild::KeyStatusChanged(const char* aSessionId,
+ uint32_t aSessionIdLength,
+ const uint8_t* aKeyId,
+ uint32_t aKeyIdLength,
+ GMPMediaKeyStatus aStatus)
+{
+ AutoTArray<uint8_t, 16> kid;
+ kid.AppendElements(aKeyId, aKeyIdLength);
+
+ nsTArray<GMPKeyInformation> keyInfos;
+ keyInfos.AppendElement(GMPKeyInformation(kid, aStatus));
+ CALL_ON_GMP_THREAD(SendBatchedKeyStatusChanged,
+ nsCString(aSessionId, aSessionIdLength),
+ keyInfos);
+}
+
+void
+GMPDecryptorChild::BatchedKeyStatusChanged(const char* aSessionId,
+ uint32_t aSessionIdLength,
+ const GMPMediaKeyInfo* aKeyInfos,
+ uint32_t aKeyInfosLength)
+{
+ nsTArray<GMPKeyInformation> keyInfos;
+ for (uint32_t i = 0; i < aKeyInfosLength; i++) {
+ nsTArray<uint8_t> keyId;
+ keyId.AppendElements(aKeyInfos[i].keyid, aKeyInfos[i].keyid_size);
+ keyInfos.AppendElement(GMPKeyInformation(keyId, aKeyInfos[i].status));
+ }
+ CALL_ON_GMP_THREAD(SendBatchedKeyStatusChanged,
+ nsCString(aSessionId, aSessionIdLength),
+ keyInfos);
+}
+
+void
+GMPDecryptorChild::Decrypted(GMPBuffer* aBuffer, GMPErr aResult)
+{
+ if (!ON_GMP_THREAD()) {
+ // We should run this whole method on the GMP thread since the buffer needs
+ // to be deleted after the SendDecrypted call.
+ mPlugin->GMPMessageLoop()->PostTask(NewRunnableMethod
+ <GMPBuffer*, GMPErr>(this,
+ &GMPDecryptorChild::Decrypted,
+ aBuffer, aResult));
+ return;
+ }
+
+ if (!aBuffer) {
+ NS_WARNING("GMPDecryptorCallback passed bull GMPBuffer");
+ return;
+ }
+
+ auto buffer = static_cast<GMPBufferImpl*>(aBuffer);
+ if (mSession) {
+ SendDecrypted(buffer->mId, aResult, buffer->mData);
+ }
+ delete buffer;
+}
+
+void
+GMPDecryptorChild::SetCapabilities(uint64_t aCaps)
+{
+ // Deprecated.
+}
+
+void
+GMPDecryptorChild::GetSandboxVoucher(const uint8_t** aVoucher,
+ uint32_t* aVoucherLength)
+{
+ if (!aVoucher || !aVoucherLength) {
+ return;
+ }
+ *aVoucher = mSandboxVoucher.Elements();
+ *aVoucherLength = mSandboxVoucher.Length();
+}
+
+void
+GMPDecryptorChild::GetPluginVoucher(const uint8_t** aVoucher,
+ uint32_t* aVoucherLength)
+{
+ if (!aVoucher || !aVoucherLength) {
+ return;
+ }
+ *aVoucher = mPluginVoucher.Elements();
+ *aVoucherLength = mPluginVoucher.Length();
+}
+
+bool
+GMPDecryptorChild::RecvInit(const bool& aDistinctiveIdentifierRequired,
+ const bool& aPersistentStateRequired)
+{
+ if (!mSession) {
+ return false;
+ }
+ mSession->Init(this, aDistinctiveIdentifierRequired, aPersistentStateRequired);
+ return true;
+}
+
+bool
+GMPDecryptorChild::RecvCreateSession(const uint32_t& aCreateSessionToken,
+ const uint32_t& aPromiseId,
+ const nsCString& aInitDataType,
+ InfallibleTArray<uint8_t>&& aInitData,
+ const GMPSessionType& aSessionType)
+{
+ if (!mSession) {
+ return false;
+ }
+
+ mSession->CreateSession(aCreateSessionToken,
+ aPromiseId,
+ aInitDataType.get(),
+ aInitDataType.Length(),
+ aInitData.Elements(),
+ aInitData.Length(),
+ aSessionType);
+
+ return true;
+}
+
+bool
+GMPDecryptorChild::RecvLoadSession(const uint32_t& aPromiseId,
+ const nsCString& aSessionId)
+{
+ if (!mSession) {
+ return false;
+ }
+
+ mSession->LoadSession(aPromiseId,
+ aSessionId.get(),
+ aSessionId.Length());
+
+ return true;
+}
+
+bool
+GMPDecryptorChild::RecvUpdateSession(const uint32_t& aPromiseId,
+ const nsCString& aSessionId,
+ InfallibleTArray<uint8_t>&& aResponse)
+{
+ if (!mSession) {
+ return false;
+ }
+
+ mSession->UpdateSession(aPromiseId,
+ aSessionId.get(),
+ aSessionId.Length(),
+ aResponse.Elements(),
+ aResponse.Length());
+
+ return true;
+}
+
+bool
+GMPDecryptorChild::RecvCloseSession(const uint32_t& aPromiseId,
+ const nsCString& aSessionId)
+{
+ if (!mSession) {
+ return false;
+ }
+
+ mSession->CloseSession(aPromiseId,
+ aSessionId.get(),
+ aSessionId.Length());
+
+ return true;
+}
+
+bool
+GMPDecryptorChild::RecvRemoveSession(const uint32_t& aPromiseId,
+ const nsCString& aSessionId)
+{
+ if (!mSession) {
+ return false;
+ }
+
+ mSession->RemoveSession(aPromiseId,
+ aSessionId.get(),
+ aSessionId.Length());
+
+ return true;
+}
+
+bool
+GMPDecryptorChild::RecvSetServerCertificate(const uint32_t& aPromiseId,
+ InfallibleTArray<uint8_t>&& aServerCert)
+{
+ if (!mSession) {
+ return false;
+ }
+
+ mSession->SetServerCertificate(aPromiseId,
+ aServerCert.Elements(),
+ aServerCert.Length());
+
+ return true;
+}
+
+bool
+GMPDecryptorChild::RecvDecrypt(const uint32_t& aId,
+ InfallibleTArray<uint8_t>&& aBuffer,
+ const GMPDecryptionData& aMetadata)
+{
+ if (!mSession) {
+ return false;
+ }
+
+ // Note: the GMPBufferImpl created here is deleted when the GMP passes
+ // it back in the Decrypted() callback above.
+ GMPBufferImpl* buffer = new GMPBufferImpl(aId, aBuffer);
+
+ // |metadata| lifetime is managed by |buffer|.
+ GMPEncryptedBufferDataImpl* metadata = new GMPEncryptedBufferDataImpl(aMetadata);
+ buffer->SetMetadata(metadata);
+
+ mSession->Decrypt(buffer, metadata);
+ return true;
+}
+
+bool
+GMPDecryptorChild::RecvDecryptingComplete()
+{
+ // Reset |mSession| before calling DecryptingComplete(). We should not send
+ // any IPC messages during tear-down.
+ auto session = mSession;
+ mSession = nullptr;
+
+ if (!session) {
+ return false;
+ }
+
+ session->DecryptingComplete();
+
+ Unused << Send__delete__(this);
+
+ return true;
+}
+
+} // namespace gmp
+} // namespace mozilla
+
+// avoid redefined macro in unified build
+#undef ON_GMP_THREAD
+#undef CALL_ON_GMP_THREAD