From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- dom/media/eme/mediadrm/MediaDrmProxySupport.cpp | 272 ++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 dom/media/eme/mediadrm/MediaDrmProxySupport.cpp (limited to 'dom/media/eme/mediadrm/MediaDrmProxySupport.cpp') diff --git a/dom/media/eme/mediadrm/MediaDrmProxySupport.cpp b/dom/media/eme/mediadrm/MediaDrmProxySupport.cpp new file mode 100644 index 0000000000..717a57df35 --- /dev/null +++ b/dom/media/eme/mediadrm/MediaDrmProxySupport.cpp @@ -0,0 +1,272 @@ +/* -*- 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 "MediaDrmProxySupport.h" +#include "MediaDrmCDMCallbackProxy.h" +#include "mozilla/EMEUtils.h" +#include "mozilla/java/MediaDrmProxyNatives.h" +#include "mozilla/java/SessionKeyInfoWrappers.h" +#include "MediaCodec.h" // For MediaDrm::KeyStatus + +namespace mozilla { + +LogModule* GetMDRMNLog() { + static LazyLogModule log("MediaDrmProxySupport"); + return log; +} + +class MediaDrmJavaCallbacksSupport + : public java::MediaDrmProxy::NativeMediaDrmProxyCallbacks::Natives< + MediaDrmJavaCallbacksSupport> { + public: + typedef java::MediaDrmProxy::NativeMediaDrmProxyCallbacks::Natives< + MediaDrmJavaCallbacksSupport> + MediaDrmProxyNativeCallbacks; + using MediaDrmProxyNativeCallbacks::AttachNative; + using MediaDrmProxyNativeCallbacks::DisposeNative; + + explicit MediaDrmJavaCallbacksSupport( + UniquePtr&& aDecryptorProxyCallback) + : mDecryptorProxyCallback(std::move(aDecryptorProxyCallback)) { + MOZ_ASSERT(mDecryptorProxyCallback); + } + /* + * Native implementation, called by Java. + */ + void OnSessionCreated(int aCreateSessionToken, int aPromiseId, + jni::ByteArray::Param aSessionId, + jni::ByteArray::Param aRequest); + + void OnSessionUpdated(int aPromiseId, jni::ByteArray::Param aSessionId); + + void OnSessionClosed(int aPromiseId, jni::ByteArray::Param aSessionId); + + void OnSessionMessage( + jni::ByteArray::Param aSessionId, + int /*mozilla::dom::MediaKeyMessageType*/ aSessionMessageType, + jni::ByteArray::Param aRequest); + + void OnSessionError(jni::ByteArray::Param aSessionId, + jni::String::Param aMessage); + + void OnSessionBatchedKeyChanged(jni::ByteArray::Param, + jni::ObjectArray::Param); + + void OnRejectPromise(int aPromiseId, jni::String::Param aMessage); + + private: + UniquePtr mDecryptorProxyCallback; +}; // MediaDrmJavaCallbacksSupport + +void MediaDrmJavaCallbacksSupport::OnSessionCreated( + int aCreateSessionToken, int aPromiseId, jni::ByteArray::Param aSessionId, + jni::ByteArray::Param aRequest) { + MOZ_ASSERT(NS_IsMainThread()); + auto reqDataArray = aRequest->GetElements(); + nsCString sessionId( + reinterpret_cast(aSessionId->GetElements().Elements()), + aSessionId->Length()); + MDRMN_LOG("SessionId(%s) closed", sessionId.get()); + + mDecryptorProxyCallback->SetSessionId(aCreateSessionToken, sessionId); + mDecryptorProxyCallback->ResolvePromise(aPromiseId); +} + +void MediaDrmJavaCallbacksSupport::OnSessionUpdated( + int aPromiseId, jni::ByteArray::Param aSessionId) { + MOZ_ASSERT(NS_IsMainThread()); + MDRMN_LOG( + "SessionId(%s) closed", + nsCString(reinterpret_cast(aSessionId->GetElements().Elements()), + aSessionId->Length()) + .get()); + mDecryptorProxyCallback->ResolvePromise(aPromiseId); +} + +void MediaDrmJavaCallbacksSupport::OnSessionClosed( + int aPromiseId, jni::ByteArray::Param aSessionId) { + MOZ_ASSERT(NS_IsMainThread()); + nsCString sessionId( + reinterpret_cast(aSessionId->GetElements().Elements()), + aSessionId->Length()); + MDRMN_LOG("SessionId(%s) closed", sessionId.get()); + mDecryptorProxyCallback->ResolvePromise(aPromiseId); + mDecryptorProxyCallback->SessionClosed(sessionId); +} + +void MediaDrmJavaCallbacksSupport::OnSessionMessage( + jni::ByteArray::Param aSessionId, + int /*mozilla::dom::MediaKeyMessageType*/ aMessageType, + jni::ByteArray::Param aRequest) { + MOZ_ASSERT(NS_IsMainThread()); + nsCString sessionId( + reinterpret_cast(aSessionId->GetElements().Elements()), + aSessionId->Length()); + auto reqDataArray = aRequest->GetElements(); + + nsTArray retRequest; + retRequest.AppendElements(reinterpret_cast(reqDataArray.Elements()), + reqDataArray.Length()); + + mDecryptorProxyCallback->SessionMessage( + sessionId, static_cast(aMessageType), + retRequest); +} + +void MediaDrmJavaCallbacksSupport::OnSessionError( + jni::ByteArray::Param aSessionId, jni::String::Param aMessage) { + MOZ_ASSERT(NS_IsMainThread()); + nsCString sessionId( + reinterpret_cast(aSessionId->GetElements().Elements()), + aSessionId->Length()); + nsCString errorMessage = aMessage->ToCString(); + MDRMN_LOG("SessionId(%s)", sessionId.get()); + // TODO: We cannot get system error code from media drm API. + // Currently use -1 as an error code. + mDecryptorProxyCallback->SessionError( + sessionId, NS_ERROR_DOM_INVALID_STATE_ERR, -1, errorMessage); +} + +// TODO: MediaDrm.KeyStatus defined the status code not included +// dom::MediaKeyStatus::Released and dom::MediaKeyStatus::Output_downscaled. +// Should keep tracking for this if it will be changed in the future. +static dom::MediaKeyStatus MediaDrmKeyStatusToMediaKeyStatus(int aStatusCode) { + using mozilla::java::sdk::MediaDrm; + switch (aStatusCode) { + case MediaDrm::KeyStatus::STATUS_USABLE: + return dom::MediaKeyStatus::Usable; + case MediaDrm::KeyStatus::STATUS_EXPIRED: + return dom::MediaKeyStatus::Expired; + case MediaDrm::KeyStatus::STATUS_OUTPUT_NOT_ALLOWED: + return dom::MediaKeyStatus::Output_restricted; + case MediaDrm::KeyStatus::STATUS_INTERNAL_ERROR: + return dom::MediaKeyStatus::Internal_error; + case MediaDrm::KeyStatus::STATUS_PENDING: + return dom::MediaKeyStatus::Status_pending; + default: + return dom::MediaKeyStatus::Internal_error; + } +} + +void MediaDrmJavaCallbacksSupport::OnSessionBatchedKeyChanged( + jni::ByteArray::Param aSessionId, jni::ObjectArray::Param aKeyInfos) { + MOZ_ASSERT(NS_IsMainThread()); + nsCString sessionId( + reinterpret_cast(aSessionId->GetElements().Elements()), + aSessionId->Length()); + nsTArray keyInfosObjectArray(aKeyInfos->GetElements()); + + nsTArray keyInfosArray; + + for (auto&& keyInfoObject : keyInfosObjectArray) { + java::SessionKeyInfo::LocalRef keyInfo(std::move(keyInfoObject)); + mozilla::jni::ByteArray::LocalRef keyIdByteArray = keyInfo->KeyId(); + nsTArray keyIdInt8Array = keyIdByteArray->GetElements(); + // Cast nsTArray to nsTArray + nsTArray* keyId = + reinterpret_cast*>(&keyIdInt8Array); + auto keyStatus = keyInfo->Status(); // int32_t + keyInfosArray.AppendElement( + CDMKeyInfo(*keyId, dom::Optional( + MediaDrmKeyStatusToMediaKeyStatus(keyStatus)))); + } + + mDecryptorProxyCallback->BatchedKeyStatusChanged(sessionId, keyInfosArray); +} + +void MediaDrmJavaCallbacksSupport::OnRejectPromise( + int aPromiseId, jni::String::Param aMessage) { + MOZ_ASSERT(NS_IsMainThread()); + nsCString reason = aMessage->ToCString(); + MDRMN_LOG("OnRejectPromise aMessage(%s) ", reason.get()); + // Current implementation assume all the reject from MediaDrm is due to + // invalid state. Other cases should be handled before calling into + // MediaDrmProxy API. + ErrorResult rv; + rv.ThrowInvalidStateError(reason); + mDecryptorProxyCallback->RejectPromise(aPromiseId, std::move(rv), reason); +} + +MediaDrmProxySupport::MediaDrmProxySupport(const nsAString& aKeySystem) + : mKeySystem(aKeySystem), mDestroyed(false) { + mJavaCallbacks = java::MediaDrmProxy::NativeMediaDrmProxyCallbacks::New(); + + mBridgeProxy = java::MediaDrmProxy::Create(mKeySystem, mJavaCallbacks); + + MOZ_ASSERT(mBridgeProxy, "mBridgeProxy should not be null"); + mMediaDrmStubId = mBridgeProxy->GetStubId()->ToString(); +} + +MediaDrmProxySupport::~MediaDrmProxySupport() { + MOZ_ASSERT(mDestroyed, "Shutdown() should be called before !!"); + MediaDrmJavaCallbacksSupport::DisposeNative(mJavaCallbacks); +} + +nsresult MediaDrmProxySupport::Init( + UniquePtr&& aCallback) { + MOZ_ASSERT(mJavaCallbacks); + + MediaDrmJavaCallbacksSupport::AttachNative( + mJavaCallbacks, + mozilla::MakeUnique(std::move(aCallback))); + return mBridgeProxy != nullptr ? NS_OK : NS_ERROR_FAILURE; +} + +void MediaDrmProxySupport::CreateSession(uint32_t aCreateSessionToken, + uint32_t aPromiseId, + const nsCString& aInitDataType, + const nsTArray& aInitData, + MediaDrmSessionType aSessionType) { + MOZ_ASSERT(mBridgeProxy); + + auto initDataBytes = mozilla::jni::ByteArray::New( + reinterpret_cast(&aInitData[0]), aInitData.Length()); + // TODO: aSessionType is not used here. + // Refer to + // http://androidxref.com/5.1.1_r6/xref/external/chromium_org/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java#420 + // it is hard code to streaming type. + mBridgeProxy->CreateSession(aCreateSessionToken, aPromiseId, + NS_ConvertUTF8toUTF16(aInitDataType), + initDataBytes); +} + +void MediaDrmProxySupport::UpdateSession(uint32_t aPromiseId, + const nsCString& aSessionId, + const nsTArray& aResponse) { + MOZ_ASSERT(mBridgeProxy); + + auto response = mozilla::jni::ByteArray::New( + reinterpret_cast(aResponse.Elements()), + aResponse.Length()); + mBridgeProxy->UpdateSession(aPromiseId, NS_ConvertUTF8toUTF16(aSessionId), + response); +} + +void MediaDrmProxySupport::CloseSession(uint32_t aPromiseId, + const nsCString& aSessionId) { + MOZ_ASSERT(mBridgeProxy); + + mBridgeProxy->CloseSession(aPromiseId, NS_ConvertUTF8toUTF16(aSessionId)); +} + +void MediaDrmProxySupport::Shutdown() { + MOZ_ASSERT(mBridgeProxy); + + if (mDestroyed) { + return; + } + mBridgeProxy->Destroy(); + mDestroyed = true; +} + +bool MediaDrmProxySupport::SetServerCertificate( + const nsTArray& aCert) { + jni::ByteArray::LocalRef cert = jni::ByteArray::New( + reinterpret_cast(aCert.Elements()), aCert.Length()); + return mBridgeProxy->SetServerCertificate(cert); +} + +} // namespace mozilla -- cgit v1.2.3