summaryrefslogtreecommitdiffstats
path: root/dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp')
-rw-r--r--dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp467
1 files changed, 467 insertions, 0 deletions
diff --git a/dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp b/dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp
new file mode 100644
index 000000000..a57d764e7
--- /dev/null
+++ b/dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp
@@ -0,0 +1,467 @@
+/* -*- 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 "mozilla/dom/MediaKeySession.h"
+#include "mozilla/MediaDrmCDMProxy.h"
+#include "MediaDrmCDMCallbackProxy.h"
+
+using namespace mozilla::java::sdk;
+
+namespace mozilla {
+
+MediaDrmSessionType
+ToMediaDrmSessionType(dom::MediaKeySessionType aSessionType)
+{
+ switch (aSessionType) {
+ case dom::MediaKeySessionType::Temporary: return kKeyStreaming;
+ case dom::MediaKeySessionType::Persistent_license: return kKeyOffline;
+ default: return kKeyStreaming;
+ };
+}
+
+MediaDrmCDMProxy::MediaDrmCDMProxy(dom::MediaKeys* aKeys,
+ const nsAString& aKeySystem,
+ bool aDistinctiveIdentifierRequired,
+ bool aPersistentStateRequired)
+ : CDMProxy(aKeys,
+ aKeySystem,
+ aDistinctiveIdentifierRequired,
+ aPersistentStateRequired)
+ , mCDM(nullptr)
+ , mShutdownCalled(false)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_COUNT_CTOR(MediaDrmCDMProxy);
+}
+
+MediaDrmCDMProxy::~MediaDrmCDMProxy()
+{
+ MOZ_COUNT_DTOR(MediaDrmCDMProxy);
+}
+
+void
+MediaDrmCDMProxy::Init(PromiseId aPromiseId,
+ const nsAString& aOrigin,
+ const nsAString& aTopLevelOrigin,
+ const nsAString& aName,
+ bool aInPrivateBrowsing)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
+
+ EME_LOG("MediaDrmCDMProxy::Init (%s, %s) %s",
+ NS_ConvertUTF16toUTF8(aOrigin).get(),
+ NS_ConvertUTF16toUTF8(aTopLevelOrigin).get(),
+ (aInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"));
+
+ // Create a thread to work with cdm.
+ if (!mOwnerThread) {
+ nsresult rv = NS_NewNamedThread("MDCDMThread", getter_AddRefs(mOwnerThread));
+ if (NS_FAILED(rv)) {
+ RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("Couldn't create CDM thread MediaDrmCDMProxy::Init"));
+ return;
+ }
+ }
+
+ mCDM = mozilla::MakeUnique<MediaDrmProxySupport>(mKeySystem);
+ nsCOMPtr<nsIRunnable> task(NewRunnableMethod<uint32_t>(this,
+ &MediaDrmCDMProxy::md_Init,
+ aPromiseId));
+ mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL);
+}
+
+void
+MediaDrmCDMProxy::CreateSession(uint32_t aCreateSessionToken,
+ MediaKeySessionType aSessionType,
+ PromiseId aPromiseId,
+ const nsAString& aInitDataType,
+ nsTArray<uint8_t>& aInitData)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(mOwnerThread);
+
+ nsAutoPtr<CreateSessionData> data(new CreateSessionData());
+ data->mSessionType = aSessionType;
+ data->mCreateSessionToken = aCreateSessionToken;
+ data->mPromiseId = aPromiseId;
+ data->mInitDataType = NS_ConvertUTF16toUTF8(aInitDataType);
+ data->mInitData = Move(aInitData);
+
+ nsCOMPtr<nsIRunnable> task(
+ NewRunnableMethod<nsAutoPtr<CreateSessionData>>(this,
+ &MediaDrmCDMProxy::md_CreateSession,
+ data));
+ mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL);
+}
+
+void
+MediaDrmCDMProxy::LoadSession(PromiseId aPromiseId,
+ const nsAString& aSessionId)
+{
+ // TODO: Implement LoadSession.
+ RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("Currently Fennec did not support LoadSession"));
+}
+
+void
+MediaDrmCDMProxy::SetServerCertificate(PromiseId aPromiseId,
+ nsTArray<uint8_t>& aCert)
+{
+ // TODO: Implement SetServerCertificate.
+ RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("Currently Fennec did not support SetServerCertificate"));
+}
+
+void
+MediaDrmCDMProxy::UpdateSession(const nsAString& aSessionId,
+ PromiseId aPromiseId,
+ nsTArray<uint8_t>& aResponse)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(mOwnerThread);
+ NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
+
+ nsAutoPtr<UpdateSessionData> data(new UpdateSessionData());
+ data->mPromiseId = aPromiseId;
+ data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId);
+ data->mResponse = Move(aResponse);
+
+ nsCOMPtr<nsIRunnable> task(
+ NewRunnableMethod<nsAutoPtr<UpdateSessionData>>(this,
+ &MediaDrmCDMProxy::md_UpdateSession,
+ data));
+ mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL);
+}
+
+void
+MediaDrmCDMProxy::CloseSession(const nsAString& aSessionId,
+ PromiseId aPromiseId)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(mOwnerThread);
+ NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
+
+ nsAutoPtr<SessionOpData> data(new SessionOpData());
+ data->mPromiseId = aPromiseId;
+ data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId);
+
+ nsCOMPtr<nsIRunnable> task(
+ NewRunnableMethod<nsAutoPtr<SessionOpData>>(this,
+ &MediaDrmCDMProxy::md_CloseSession,
+ data));
+ mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL);
+}
+
+void
+MediaDrmCDMProxy::RemoveSession(const nsAString& aSessionId,
+ PromiseId aPromiseId)
+{
+ // TODO: Implement RemoveSession.
+ RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("Currently Fennec did not support RemoveSession"));
+}
+
+void
+MediaDrmCDMProxy::Shutdown()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(mOwnerThread);
+ nsCOMPtr<nsIRunnable> task(
+ NewRunnableMethod(this, &MediaDrmCDMProxy::md_Shutdown));
+
+ mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL);
+ mOwnerThread->Shutdown();
+ mOwnerThread = nullptr;
+}
+
+void
+MediaDrmCDMProxy::Terminated()
+{
+ // TODO: Implement Terminated.
+ // Should find a way to handle the case when remote side MediaDrm crashed.
+}
+
+const nsCString&
+MediaDrmCDMProxy::GetNodeId() const
+{
+ return mNodeId;
+}
+
+void
+MediaDrmCDMProxy::OnSetSessionId(uint32_t aCreateSessionToken,
+ const nsAString& aSessionId)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (mKeys.IsNull()) {
+ return;
+ }
+
+ RefPtr<dom::MediaKeySession> session(mKeys->GetPendingSession(aCreateSessionToken));
+ if (session) {
+ session->SetSessionId(aSessionId);
+ }
+}
+
+void
+MediaDrmCDMProxy::OnResolveLoadSessionPromise(uint32_t aPromiseId, bool aSuccess)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (mKeys.IsNull()) {
+ return;
+ }
+ mKeys->OnSessionLoaded(aPromiseId, aSuccess);
+}
+
+void
+MediaDrmCDMProxy::OnSessionMessage(const nsAString& aSessionId,
+ dom::MediaKeyMessageType aMessageType,
+ nsTArray<uint8_t>& aMessage)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (mKeys.IsNull()) {
+ return;
+ }
+ RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
+ if (session) {
+ session->DispatchKeyMessage(aMessageType, aMessage);
+ }
+}
+
+void
+MediaDrmCDMProxy::OnExpirationChange(const nsAString& aSessionId,
+ UnixTime aExpiryTime)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (mKeys.IsNull()) {
+ return;
+ }
+ RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
+ if (session) {
+ session->SetExpiration(static_cast<double>(aExpiryTime));
+ }
+}
+
+void
+MediaDrmCDMProxy::OnSessionClosed(const nsAString& aSessionId)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (mKeys.IsNull()) {
+ return;
+ }
+ RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
+ if (session) {
+ session->OnClosed();
+ }
+}
+
+void
+MediaDrmCDMProxy::OnSessionError(const nsAString& aSessionId,
+ nsresult aException,
+ uint32_t aSystemCode,
+ const nsAString& aMsg)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (mKeys.IsNull()) {
+ return;
+ }
+ RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
+ if (session) {
+ session->DispatchKeyError(aSystemCode);
+ }
+}
+
+void
+MediaDrmCDMProxy::OnRejectPromise(uint32_t aPromiseId,
+ nsresult aDOMException,
+ const nsCString& aMsg)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ RejectPromise(aPromiseId, aDOMException, aMsg);
+}
+
+RefPtr<MediaDrmCDMProxy::DecryptPromise>
+MediaDrmCDMProxy::Decrypt(MediaRawData* aSample)
+{
+ MOZ_ASSERT_UNREACHABLE("Fennec could not handle decrypting individually");
+ return nullptr;
+}
+
+void
+MediaDrmCDMProxy::OnDecrypted(uint32_t aId,
+ DecryptStatus aResult,
+ const nsTArray<uint8_t>& aDecryptedData)
+{
+ MOZ_ASSERT_UNREACHABLE("Fennec could not handle decrypted event");
+}
+
+void
+MediaDrmCDMProxy::RejectPromise(PromiseId aId, nsresult aCode,
+ const nsCString& aReason)
+{
+ if (NS_IsMainThread()) {
+ if (!mKeys.IsNull()) {
+ mKeys->RejectPromise(aId, aCode, aReason);
+ }
+ } else {
+ nsCOMPtr<nsIRunnable> task(new RejectPromiseTask(this, aId, aCode,
+ aReason));
+ NS_DispatchToMainThread(task);
+ }
+}
+
+void
+MediaDrmCDMProxy::ResolvePromise(PromiseId aId)
+{
+ if (NS_IsMainThread()) {
+ if (!mKeys.IsNull()) {
+ mKeys->ResolvePromise(aId);
+ } else {
+ NS_WARNING("MediaDrmCDMProxy unable to resolve promise!");
+ }
+ } else {
+ nsCOMPtr<nsIRunnable> task;
+ task = NewRunnableMethod<PromiseId>(this,
+ &MediaDrmCDMProxy::ResolvePromise,
+ aId);
+ NS_DispatchToMainThread(task);
+ }
+}
+
+const nsString&
+MediaDrmCDMProxy::KeySystem() const
+{
+ return mKeySystem;
+}
+
+CDMCaps&
+MediaDrmCDMProxy::Capabilites()
+{
+ return mCapabilites;
+}
+
+void
+MediaDrmCDMProxy::OnKeyStatusesChange(const nsAString& aSessionId)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (mKeys.IsNull()) {
+ return;
+ }
+ RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
+ if (session) {
+ session->DispatchKeyStatusesChange();
+ }
+}
+
+void
+MediaDrmCDMProxy::GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
+ nsTArray<nsCString>& aSessionIds)
+{
+ CDMCaps::AutoLock caps(Capabilites());
+ caps.GetSessionIdsForKeyId(aKeyId, aSessionIds);
+}
+
+#ifdef DEBUG
+bool
+MediaDrmCDMProxy::IsOnOwnerThread()
+{
+ return NS_GetCurrentThread() == mOwnerThread;
+}
+#endif
+
+void
+MediaDrmCDMProxy::OnCDMCreated(uint32_t aPromiseId)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (mKeys.IsNull()) {
+ return;
+ }
+
+ if (mCDM) {
+ mKeys->OnCDMCreated(aPromiseId, GetNodeId(), 0);
+ return;
+ }
+
+ // No CDM? Just reject the promise.
+ mKeys->RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("Null CDM in OnCDMCreated()"));
+}
+
+void
+MediaDrmCDMProxy::md_Init(uint32_t aPromiseId)
+{
+ MOZ_ASSERT(IsOnOwnerThread());
+ MOZ_ASSERT(mCDM);
+
+ mCallback = new MediaDrmCDMCallbackProxy(this);
+ mCDM->Init(mCallback);
+ nsCOMPtr<nsIRunnable> task(
+ NewRunnableMethod<uint32_t>(this,
+ &MediaDrmCDMProxy::OnCDMCreated,
+ aPromiseId));
+ NS_DispatchToMainThread(task);
+}
+
+void
+MediaDrmCDMProxy::md_CreateSession(nsAutoPtr<CreateSessionData> aData)
+{
+ MOZ_ASSERT(IsOnOwnerThread());
+
+ if (!mCDM) {
+ RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("Null CDM in md_CreateSession"));
+ return;
+ }
+
+ mCDM->CreateSession(aData->mCreateSessionToken,
+ aData->mPromiseId,
+ aData->mInitDataType,
+ aData->mInitData,
+ ToMediaDrmSessionType(aData->mSessionType));
+}
+
+void
+MediaDrmCDMProxy::md_UpdateSession(nsAutoPtr<UpdateSessionData> aData)
+{
+ MOZ_ASSERT(IsOnOwnerThread());
+
+ if (!mCDM) {
+ RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("Null CDM in md_UpdateSession"));
+ return;
+ }
+ mCDM->UpdateSession(aData->mPromiseId,
+ aData->mSessionId,
+ aData->mResponse);
+}
+
+void
+MediaDrmCDMProxy::md_CloseSession(nsAutoPtr<SessionOpData> aData)
+{
+ MOZ_ASSERT(IsOnOwnerThread());
+
+ if (!mCDM) {
+ RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("Null CDM in md_CloseSession"));
+ return;
+ }
+ mCDM->CloseSession(aData->mPromiseId, aData->mSessionId);
+}
+
+void
+MediaDrmCDMProxy::md_Shutdown()
+{
+ MOZ_ASSERT(IsOnOwnerThread());
+ MOZ_ASSERT(mCDM);
+ if (mShutdownCalled) {
+ return;
+ }
+ mShutdownCalled = true;
+ mCDM->Shutdown();
+ mCDM = nullptr;
+}
+
+} // namespace mozilla \ No newline at end of file