Bug 1315850 - Implement ChromiumCDMProxy initialization. r=gerald
This means the MediaKeys is able to create a CDM.
MozReview-Commit-ID: 94Xc7sCLhH3
--- a/dom/media/gmp/ChromiumCDMParent.cpp
+++ b/dom/media/gmp/ChromiumCDMParent.cpp
@@ -1,25 +1,38 @@
/* -*- 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 "ChromiumCDMParent.h"
#include "mozilla/gmp/GMPTypes.h"
#include "GMPContentChild.h"
+#include "mozilla/Unused.h"
+#include "ChromiumCDMProxy.h"
namespace mozilla {
namespace gmp {
-ChromiumCDMParent::ChromiumCDMParent(GMPContentParent* aContentParent)
- : mContentParent(aContentParent)
+ChromiumCDMParent::ChromiumCDMParent(GMPContentParent* aContentParent,
+ uint32_t aPluginId)
+ : mPluginId(aPluginId)
+ , mContentParent(aContentParent)
{
}
+bool
+ChromiumCDMParent::Init(ChromiumCDMProxy* aProxy,
+ bool aAllowDistinctiveIdentifier,
+ bool aAllowPersistentState)
+{
+ mProxy = aProxy;
+ return SendInit(aAllowDistinctiveIdentifier, aAllowPersistentState);
+}
+
ipc::IPCResult
ChromiumCDMParent::Recv__delete__()
{
return IPC_OK();
}
ipc::IPCResult
ChromiumCDMParent::RecvOnResolveNewSessionPromise(const uint32_t& aPromiseId,
--- a/dom/media/gmp/ChromiumCDMParent.h
+++ b/dom/media/gmp/ChromiumCDMParent.h
@@ -8,28 +8,37 @@
#include "GMPCrashHelper.h"
#include "GMPCrashHelperHolder.h"
#include "GMPMessageUtils.h"
#include "mozilla/gmp/PChromiumCDMParent.h"
#include "mozilla/RefPtr.h"
namespace mozilla {
+
+class ChromiumCDMProxy;
+
namespace gmp {
class GMPContentParent;
class ChromiumCDMParent final
: public PChromiumCDMParent
, public GMPCrashHelperHolder
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ChromiumCDMParent)
- explicit ChromiumCDMParent(GMPContentParent* aContentParent);
+ ChromiumCDMParent(GMPContentParent* aContentParent, uint32_t aPluginId);
+
+ uint32_t PluginId() const { return mPluginId; }
+
+ bool Init(ChromiumCDMProxy* aProxy,
+ bool aAllowDistinctiveIdentifier,
+ bool aAllowPersistentState);
// TODO: Add functions for clients to send data to CDM, and
// a Close() function.
protected:
~ChromiumCDMParent() {}
ipc::IPCResult Recv__delete__() override;
@@ -57,15 +66,20 @@ protected:
const nsCString& aMessage) override;
ipc::IPCResult RecvDecrypted(const uint32_t& aStatus,
nsTArray<uint8_t>&& aData) override;
ipc::IPCResult RecvDecoded(const CDMVideoFrame& aFrame) override;
ipc::IPCResult RecvDecodeFailed(const uint32_t& aStatus) override;
ipc::IPCResult RecvShutdown() override;
void ActorDestroy(ActorDestroyReason aWhy) override;
+ const uint32_t mPluginId;
GMPContentParent* mContentParent;
+ // Note: this pointer is a weak reference because otherwise it would cause
+ // a cycle, as ChromiumCDMProxy has a strong reference to the
+ // ChromiumCDMParent.
+ ChromiumCDMProxy* mProxy = nullptr;
};
} // namespace gmp
} // namespace mozilla
#endif // ChromiumCDMParent_h_
--- a/dom/media/gmp/ChromiumCDMProxy.cpp
+++ b/dom/media/gmp/ChromiumCDMProxy.cpp
@@ -1,16 +1,18 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ChromiumCDMProxy.h"
#include "GMPUtils.h"
+#include "nsPrintfCString.h"
+#include "GMPService.h"
namespace mozilla {
ChromiumCDMProxy::ChromiumCDMProxy(dom::MediaKeys* aKeys,
const nsAString& aKeySystem,
GMPCrashHelper* aCrashHelper,
bool aDistinctiveIdentifierRequired,
bool aPersistentStateRequired,
@@ -34,16 +36,105 @@ ChromiumCDMProxy::~ChromiumCDMProxy()
}
void
ChromiumCDMProxy::Init(PromiseId aPromiseId,
const nsAString& aOrigin,
const nsAString& aTopLevelOrigin,
const nsAString& aGMPName)
{
+ MOZ_ASSERT(NS_IsMainThread());
+ NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
+
+ EME_LOG("ChromiumCDMProxy::Init(%s, %s)",
+ NS_ConvertUTF16toUTF8(aOrigin).get(),
+ NS_ConvertUTF16toUTF8(aTopLevelOrigin).get());
+
+ if (!mGMPThread) {
+ RejectPromise(
+ aPromiseId,
+ NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("Couldn't get GMP thread ChromiumCDMProxy::Init"));
+ return;
+ }
+
+ if (aGMPName.IsEmpty()) {
+ RejectPromise(aPromiseId,
+ NS_ERROR_DOM_INVALID_STATE_ERR,
+ nsPrintfCString("Unknown GMP for keysystem '%s'",
+ NS_ConvertUTF16toUTF8(mKeySystem).get()));
+ return;
+ }
+
+ gmp::NodeId nodeId(aOrigin, aTopLevelOrigin, aGMPName);
+ RefPtr<AbstractThread> thread = mGMPThread;
+ RefPtr<GMPCrashHelper> helper(mCrashHelper);
+ RefPtr<ChromiumCDMProxy> self(this);
+ nsCString keySystem = NS_ConvertUTF16toUTF8(mKeySystem);
+ RefPtr<Runnable> task(NS_NewRunnableFunction(
+ [self, nodeId, helper, aPromiseId, thread, keySystem]() -> void {
+ MOZ_ASSERT(self->IsOnOwnerThread());
+
+ RefPtr<gmp::GeckoMediaPluginService> service =
+ gmp::GeckoMediaPluginService::GetGeckoMediaPluginService();
+ if (!service) {
+ self->RejectPromise(
+ aPromiseId,
+ NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING(
+ "Couldn't get GeckoMediaPluginService in ChromiumCDMProxy::Init"));
+ return;
+ }
+ RefPtr<gmp::GetCDMParentPromise> promise =
+ service->GetCDM(nodeId, { keySystem }, helper);
+ promise->Then(
+ thread,
+ __func__,
+ [self, aPromiseId](RefPtr<gmp::ChromiumCDMParent> cdm) {
+ if (!cdm->Init(self,
+ self->mDistinctiveIdentifierRequired,
+ self->mPersistentStateRequired)) {
+ self->RejectPromise(aPromiseId,
+ NS_ERROR_FAILURE,
+ NS_LITERAL_CSTRING("GetCDM failed."));
+ return;
+ }
+ self->mCDM = cdm;
+ self->OnCDMCreated(aPromiseId);
+ },
+ [self, aPromiseId](nsresult rv) {
+ self->RejectPromise(
+ aPromiseId, NS_ERROR_FAILURE, NS_LITERAL_CSTRING("GetCDM failed."));
+ });
+ }));
+
+ mGMPThread->Dispatch(task.forget());
+}
+
+void
+ChromiumCDMProxy::OnCDMCreated(uint32_t aPromiseId)
+{
+ EME_LOG("ChromiumCDMProxy::OnCDMCreated(pid=%u) isMainThread=%d this=%p",
+ aPromiseId,
+ NS_IsMainThread(),
+ this);
+
+ if (!NS_IsMainThread()) {
+ mMainThread->Dispatch(NewRunnableMethod<PromiseId>(
+ this, &ChromiumCDMProxy::OnCDMCreated, aPromiseId),
+ NS_DISPATCH_NORMAL);
+ return;
+ }
+ // This should only be called once the CDM has been created.
+ MOZ_ASSERT(mCDM);
+ MOZ_ASSERT(NS_IsMainThread());
+ if (mKeys.IsNull()) {
+ return;
+ }
+ mKeys->OnCDMCreated(aPromiseId, mCDM->PluginId());
}
#ifdef DEBUG
bool
ChromiumCDMProxy::IsOnOwnerThread()
{
return mGMPThread->IsCurrentThreadIn();
}
@@ -93,21 +184,44 @@ ChromiumCDMProxy::Shutdown()
{
}
void
ChromiumCDMProxy::RejectPromise(PromiseId aId,
nsresult aCode,
const nsCString& aReason)
{
+ if (!NS_IsMainThread()) {
+ nsCOMPtr<nsIRunnable> task;
+ task = NewRunnableMethod<PromiseId, nsresult, nsCString>(
+ this, &ChromiumCDMProxy::RejectPromise, aId, aCode, aReason);
+ NS_DispatchToMainThread(task);
+ return;
+ }
+ if (!mKeys.IsNull()) {
+ mKeys->RejectPromise(aId, aCode, aReason);
+ }
}
void
ChromiumCDMProxy::ResolvePromise(PromiseId aId)
{
+ if (!NS_IsMainThread()) {
+ nsCOMPtr<nsIRunnable> task;
+ task = NewRunnableMethod<PromiseId>(
+ this, &ChromiumCDMProxy::ResolvePromise, aId);
+ NS_DispatchToMainThread(task);
+ return;
+ }
+
+ if (!mKeys.IsNull()) {
+ mKeys->ResolvePromise(aId);
+ } else {
+ NS_WARNING("ChromiumCDMProxy unable to resolve promise!");
+ }
}
const nsCString&
ChromiumCDMProxy::GetNodeId() const
{
return mNodeId;
}
--- a/dom/media/gmp/ChromiumCDMProxy.h
+++ b/dom/media/gmp/ChromiumCDMProxy.h
@@ -103,16 +103,18 @@ public:
void GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
nsTArray<nsCString>& aSessionIds) override;
#ifdef DEBUG
bool IsOnOwnerThread() override;
#endif
private:
+ void OnCDMCreated(uint32_t aPromiseId);
+
~ChromiumCDMProxy();
GMPCrashHelper* mCrashHelper;
RefPtr<gmp::ChromiumCDMParent> mCDM;
RefPtr<AbstractThread> mGMPThread;
};
--- a/dom/media/gmp/GMPContentParent.cpp
+++ b/dom/media/gmp/GMPContentParent.cpp
@@ -238,17 +238,17 @@ GMPContentParent::GetGMPVideoEncoder(GMP
mVideoEncoders.AppendElement(vep);
return NS_OK;
}
PChromiumCDMParent*
GMPContentParent::AllocPChromiumCDMParent()
{
- ChromiumCDMParent* parent = new ChromiumCDMParent(this);
+ ChromiumCDMParent* parent = new ChromiumCDMParent(this, GetPluginId());
NS_ADDREF(parent);
return parent;
}
PGMPVideoDecoderParent*
GMPContentParent::AllocPGMPVideoDecoderParent(const uint32_t& aDecryptorId)
{
GMPVideoDecoderParent* vdp = new GMPVideoDecoderParent(this);