tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MediaDrmProxySupport.cpp (10571B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "MediaDrmProxySupport.h"
      8 
      9 #include "MediaCodec.h"  // For MediaDrm::KeyStatus
     10 #include "MediaDrmCDMCallbackProxy.h"
     11 #include "mozilla/EMEUtils.h"
     12 #include "mozilla/java/MediaDrmProxyNatives.h"
     13 #include "mozilla/java/SessionKeyInfoWrappers.h"
     14 
     15 namespace mozilla {
     16 
     17 LogModule* GetMDRMNLog() {
     18  static LazyLogModule log("MediaDrmProxySupport");
     19  return log;
     20 }
     21 
     22 class MediaDrmJavaCallbacksSupport
     23    : public java::MediaDrmProxy::NativeMediaDrmProxyCallbacks::Natives<
     24          MediaDrmJavaCallbacksSupport> {
     25 public:
     26  typedef java::MediaDrmProxy::NativeMediaDrmProxyCallbacks::Natives<
     27      MediaDrmJavaCallbacksSupport>
     28      MediaDrmProxyNativeCallbacks;
     29  using MediaDrmProxyNativeCallbacks::AttachNative;
     30  using MediaDrmProxyNativeCallbacks::DisposeNative;
     31 
     32  explicit MediaDrmJavaCallbacksSupport(
     33      UniquePtr<MediaDrmCDMCallbackProxy>&& aDecryptorProxyCallback)
     34      : mDecryptorProxyCallback(std::move(aDecryptorProxyCallback)) {
     35    MOZ_ASSERT(mDecryptorProxyCallback);
     36  }
     37  /*
     38   * Native implementation, called by Java.
     39   */
     40  void OnSessionCreated(int aCreateSessionToken, int aPromiseId,
     41                        jni::ByteArray::Param aSessionId,
     42                        jni::ByteArray::Param aRequest);
     43 
     44  void OnSessionUpdated(int aPromiseId, jni::ByteArray::Param aSessionId);
     45 
     46  void OnSessionClosed(int aPromiseId, jni::ByteArray::Param aSessionId);
     47 
     48  void OnSessionMessage(
     49      jni::ByteArray::Param aSessionId,
     50      int /*mozilla::dom::MediaKeyMessageType*/ aSessionMessageType,
     51      jni::ByteArray::Param aRequest);
     52 
     53  void OnSessionError(jni::ByteArray::Param aSessionId,
     54                      jni::String::Param aMessage);
     55 
     56  void OnSessionBatchedKeyChanged(jni::ByteArray::Param,
     57                                  jni::ObjectArray::Param);
     58 
     59  void OnRejectPromise(int aPromiseId, jni::String::Param aMessage);
     60 
     61 private:
     62  UniquePtr<MediaDrmCDMCallbackProxy> mDecryptorProxyCallback;
     63 };  // MediaDrmJavaCallbacksSupport
     64 
     65 void MediaDrmJavaCallbacksSupport::OnSessionCreated(
     66    int aCreateSessionToken, int aPromiseId, jni::ByteArray::Param aSessionId,
     67    jni::ByteArray::Param aRequest) {
     68  MOZ_ASSERT(NS_IsMainThread());
     69  auto reqDataArray = aRequest->GetElements();
     70  nsCString sessionId(
     71      reinterpret_cast<char*>(aSessionId->GetElements().Elements()),
     72      aSessionId->Length());
     73  MDRMN_LOG("SessionId(%s) closed", sessionId.get());
     74 
     75  mDecryptorProxyCallback->SetSessionId(aCreateSessionToken, sessionId);
     76  mDecryptorProxyCallback->ResolvePromise(aPromiseId);
     77 }
     78 
     79 void MediaDrmJavaCallbacksSupport::OnSessionUpdated(
     80    int aPromiseId, jni::ByteArray::Param aSessionId) {
     81  MOZ_ASSERT(NS_IsMainThread());
     82  MDRMN_LOG(
     83      "SessionId(%s) closed",
     84      nsCString(reinterpret_cast<char*>(aSessionId->GetElements().Elements()),
     85                aSessionId->Length())
     86          .get());
     87  mDecryptorProxyCallback->ResolvePromise(aPromiseId);
     88 }
     89 
     90 void MediaDrmJavaCallbacksSupport::OnSessionClosed(
     91    int aPromiseId, jni::ByteArray::Param aSessionId) {
     92  MOZ_ASSERT(NS_IsMainThread());
     93  nsCString sessionId(
     94      reinterpret_cast<char*>(aSessionId->GetElements().Elements()),
     95      aSessionId->Length());
     96  MDRMN_LOG("SessionId(%s) closed", sessionId.get());
     97  mDecryptorProxyCallback->ResolvePromise(aPromiseId);
     98  mDecryptorProxyCallback->SessionClosed(sessionId);
     99 }
    100 
    101 void MediaDrmJavaCallbacksSupport::OnSessionMessage(
    102    jni::ByteArray::Param aSessionId,
    103    int /*mozilla::dom::MediaKeyMessageType*/ aMessageType,
    104    jni::ByteArray::Param aRequest) {
    105  MOZ_ASSERT(NS_IsMainThread());
    106  nsCString sessionId(
    107      reinterpret_cast<char*>(aSessionId->GetElements().Elements()),
    108      aSessionId->Length());
    109  auto reqDataArray = aRequest->GetElements();
    110 
    111  nsTArray<uint8_t> retRequest;
    112  retRequest.AppendElements(reinterpret_cast<uint8_t*>(reqDataArray.Elements()),
    113                            reqDataArray.Length());
    114 
    115  mDecryptorProxyCallback->SessionMessage(
    116      sessionId, static_cast<dom::MediaKeyMessageType>(aMessageType),
    117      retRequest);
    118 }
    119 
    120 void MediaDrmJavaCallbacksSupport::OnSessionError(
    121    jni::ByteArray::Param aSessionId, jni::String::Param aMessage) {
    122  MOZ_ASSERT(NS_IsMainThread());
    123  nsCString sessionId(
    124      reinterpret_cast<char*>(aSessionId->GetElements().Elements()),
    125      aSessionId->Length());
    126  nsCString errorMessage = aMessage->ToCString();
    127  MDRMN_LOG("SessionId(%s)", sessionId.get());
    128  // TODO: We cannot get system error code from media drm API.
    129  // Currently use -1 as an error code.
    130  mDecryptorProxyCallback->SessionError(
    131      sessionId, NS_ERROR_DOM_INVALID_STATE_ERR, -1, errorMessage);
    132 }
    133 
    134 // TODO: MediaDrm.KeyStatus defined the status code not included
    135 // dom::MediaKeyStatus::Released and dom::MediaKeyStatus::Output_downscaled.
    136 // Should keep tracking for this if it will be changed in the future.
    137 static dom::MediaKeyStatus MediaDrmKeyStatusToMediaKeyStatus(int aStatusCode) {
    138  using mozilla::java::sdk::MediaDrm;
    139  switch (aStatusCode) {
    140    case MediaDrm::KeyStatus::STATUS_USABLE:
    141      return dom::MediaKeyStatus::Usable;
    142    case MediaDrm::KeyStatus::STATUS_EXPIRED:
    143      return dom::MediaKeyStatus::Expired;
    144    case MediaDrm::KeyStatus::STATUS_OUTPUT_NOT_ALLOWED:
    145      return dom::MediaKeyStatus::Output_restricted;
    146    case MediaDrm::KeyStatus::STATUS_INTERNAL_ERROR:
    147      return dom::MediaKeyStatus::Internal_error;
    148    case MediaDrm::KeyStatus::STATUS_PENDING:
    149      return dom::MediaKeyStatus::Status_pending;
    150    default:
    151      return dom::MediaKeyStatus::Internal_error;
    152  }
    153 }
    154 
    155 void MediaDrmJavaCallbacksSupport::OnSessionBatchedKeyChanged(
    156    jni::ByteArray::Param aSessionId, jni::ObjectArray::Param aKeyInfos) {
    157  MOZ_ASSERT(NS_IsMainThread());
    158  nsCString sessionId(
    159      reinterpret_cast<char*>(aSessionId->GetElements().Elements()),
    160      aSessionId->Length());
    161  nsTArray<jni::Object::LocalRef> keyInfosObjectArray(aKeyInfos->GetElements());
    162 
    163  nsTArray<CDMKeyInfo> keyInfosArray;
    164 
    165  for (auto&& keyInfoObject : keyInfosObjectArray) {
    166    java::SessionKeyInfo::LocalRef keyInfo(std::move(keyInfoObject));
    167    mozilla::jni::ByteArray::LocalRef keyIdByteArray = keyInfo->KeyId();
    168    nsTArray<int8_t> keyIdInt8Array = keyIdByteArray->GetElements();
    169    // Cast nsTArray<int8_t> to nsTArray<uint8_t>
    170    nsTArray<uint8_t>* keyId =
    171        reinterpret_cast<nsTArray<uint8_t>*>(&keyIdInt8Array);
    172    auto keyStatus = keyInfo->Status();  // int32_t
    173    keyInfosArray.AppendElement(
    174        CDMKeyInfo(*keyId, dom::Optional<dom::MediaKeyStatus>(
    175                               MediaDrmKeyStatusToMediaKeyStatus(keyStatus))));
    176  }
    177 
    178  mDecryptorProxyCallback->BatchedKeyStatusChanged(sessionId, keyInfosArray);
    179 }
    180 
    181 void MediaDrmJavaCallbacksSupport::OnRejectPromise(
    182    int aPromiseId, jni::String::Param aMessage) {
    183  MOZ_ASSERT(NS_IsMainThread());
    184  nsCString reason = aMessage->ToCString();
    185  MDRMN_LOG("OnRejectPromise aMessage(%s) ", reason.get());
    186  // Current implementation assume all the reject from MediaDrm is due to
    187  // invalid state. Other cases should be handled before calling into
    188  // MediaDrmProxy API.
    189  ErrorResult rv;
    190  rv.ThrowInvalidStateError(reason);
    191  mDecryptorProxyCallback->RejectPromise(aPromiseId, std::move(rv), reason);
    192 }
    193 
    194 MediaDrmProxySupport::MediaDrmProxySupport(const nsAString& aKeySystem)
    195    : mKeySystem(aKeySystem), mDestroyed(false) {
    196  mJavaCallbacks = java::MediaDrmProxy::NativeMediaDrmProxyCallbacks::New();
    197 
    198  mBridgeProxy = java::MediaDrmProxy::Create(mKeySystem, mJavaCallbacks);
    199 
    200  MOZ_ASSERT(mBridgeProxy, "mBridgeProxy should not be null");
    201  mMediaDrmStubId = mBridgeProxy->GetStubId()->ToString();
    202 }
    203 
    204 MediaDrmProxySupport::~MediaDrmProxySupport() {
    205  MOZ_ASSERT(mDestroyed, "Shutdown() should be called before !!");
    206  MediaDrmJavaCallbacksSupport::DisposeNative(mJavaCallbacks);
    207 }
    208 
    209 nsresult MediaDrmProxySupport::Init(
    210    UniquePtr<MediaDrmCDMCallbackProxy>&& aCallback) {
    211  MOZ_ASSERT(mJavaCallbacks);
    212 
    213  MediaDrmJavaCallbacksSupport::AttachNative(
    214      mJavaCallbacks,
    215      mozilla::MakeUnique<MediaDrmJavaCallbacksSupport>(std::move(aCallback)));
    216  return mBridgeProxy != nullptr ? NS_OK : NS_ERROR_FAILURE;
    217 }
    218 
    219 void MediaDrmProxySupport::CreateSession(uint32_t aCreateSessionToken,
    220                                         uint32_t aPromiseId,
    221                                         const nsCString& aInitDataType,
    222                                         const nsTArray<uint8_t>& aInitData,
    223                                         MediaDrmSessionType aSessionType) {
    224  MOZ_ASSERT(mBridgeProxy);
    225 
    226  auto initDataBytes = mozilla::jni::ByteArray::New(
    227      reinterpret_cast<const int8_t*>(aInitData.Elements()),
    228      aInitData.Length());
    229  // TODO: aSessionType is not used here.
    230  // Refer to
    231  // http://androidxref.com/5.1.1_r6/xref/external/chromium_org/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java#420
    232  // it is hard code to streaming type.
    233  mBridgeProxy->CreateSession(aCreateSessionToken, aPromiseId,
    234                              NS_ConvertUTF8toUTF16(aInitDataType),
    235                              initDataBytes);
    236 }
    237 
    238 void MediaDrmProxySupport::UpdateSession(uint32_t aPromiseId,
    239                                         const nsCString& aSessionId,
    240                                         const nsTArray<uint8_t>& aResponse) {
    241  MOZ_ASSERT(mBridgeProxy);
    242 
    243  auto response = mozilla::jni::ByteArray::New(
    244      reinterpret_cast<const int8_t*>(aResponse.Elements()),
    245      aResponse.Length());
    246  mBridgeProxy->UpdateSession(aPromiseId, NS_ConvertUTF8toUTF16(aSessionId),
    247                              response);
    248 }
    249 
    250 void MediaDrmProxySupport::CloseSession(uint32_t aPromiseId,
    251                                        const nsCString& aSessionId) {
    252  MOZ_ASSERT(mBridgeProxy);
    253 
    254  mBridgeProxy->CloseSession(aPromiseId, NS_ConvertUTF8toUTF16(aSessionId));
    255 }
    256 
    257 void MediaDrmProxySupport::Shutdown() {
    258  MOZ_ASSERT(mBridgeProxy);
    259 
    260  if (mDestroyed) {
    261    return;
    262  }
    263  mBridgeProxy->Destroy();
    264  mDestroyed = true;
    265 }
    266 
    267 bool MediaDrmProxySupport::SetServerCertificate(
    268    const nsTArray<uint8_t>& aCert) {
    269  jni::ByteArray::LocalRef cert = jni::ByteArray::New(
    270      reinterpret_cast<const int8_t*>(aCert.Elements()), aCert.Length());
    271  return mBridgeProxy->SetServerCertificate(cert);
    272 }
    273 
    274 }  // namespace mozilla