tor-browser

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

UtilityMediaServiceChild.cpp (8931B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 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
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "UtilityMediaServiceChild.h"
      8 
      9 #include "base/basictypes.h"
     10 #include "mozilla/AppShutdown.h"
     11 #include "mozilla/dom/ContentParent.h"
     12 #include "mozilla/gfx/gfxVars.h"
     13 
     14 #ifdef MOZ_WMF_MEDIA_ENGINE
     15 #  include "mozilla/StaticPrefs_media.h"
     16 #  include "mozilla/gfx/GPUProcessManager.h"
     17 #  include "mozilla/ipc/UtilityProcessManager.h"
     18 #  include "mozilla/layers/PVideoBridge.h"
     19 #  include "mozilla/layers/VideoBridgeParent.h"
     20 #  include "mozilla/layers/VideoBridgeUtils.h"
     21 #endif
     22 
     23 #ifdef MOZ_WMF_CDM
     24 #  include "mozilla/dom/Promise.h"
     25 #  include "mozilla/EMEUtils.h"
     26 #  include "mozilla/PMFCDM.h"
     27 #endif
     28 
     29 namespace mozilla::ipc {
     30 
     31 NS_IMETHODIMP UtilityMediaServiceChildShutdownObserver::Observe(
     32    nsISupports* aSubject, const char* aTopic, const char16_t* aData) {
     33  MOZ_ASSERT(strcmp(aTopic, "ipc:utility-shutdown") == 0);
     34 
     35  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
     36  if (observerService) {
     37    observerService->RemoveObserver(this, "ipc:utility-shutdown");
     38  }
     39 
     40  UtilityMediaServiceChild::Shutdown(mSandbox);
     41  return NS_OK;
     42 }
     43 
     44 NS_IMPL_ISUPPORTS(UtilityMediaServiceChildShutdownObserver, nsIObserver);
     45 
     46 static EnumeratedArray<SandboxingKind, StaticRefPtr<UtilityMediaServiceChild>,
     47                       size_t(SandboxingKind::COUNT)>
     48    sAudioDecoderChilds;
     49 
     50 UtilityMediaServiceChild::UtilityMediaServiceChild(SandboxingKind aKind)
     51    : mSandbox(aKind), mAudioDecoderChildStart(TimeStamp::Now()) {
     52  MOZ_ASSERT(NS_IsMainThread());
     53  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
     54  if (observerService) {
     55    auto* obs = new UtilityMediaServiceChildShutdownObserver(aKind);
     56    observerService->AddObserver(obs, "ipc:utility-shutdown", false);
     57  }
     58 }
     59 
     60 nsresult UtilityMediaServiceChild::BindToUtilityProcess(
     61    RefPtr<UtilityProcessParent> aUtilityParent) {
     62  Endpoint<PUtilityMediaServiceChild> utilityMediaServiceChildEnd;
     63  Endpoint<PUtilityMediaServiceParent> utilityMediaServiceParentEnd;
     64  nsresult rv = PUtilityMediaService::CreateEndpoints(
     65      aUtilityParent->OtherEndpointProcInfo(), EndpointProcInfo::Current(),
     66      &utilityMediaServiceParentEnd, &utilityMediaServiceChildEnd);
     67 
     68  if (NS_FAILED(rv)) {
     69    MOZ_ASSERT(false, "Protocol endpoints failure");
     70    return NS_ERROR_FAILURE;
     71  }
     72 
     73  nsTArray<gfx::GfxVarUpdate> updates = gfx::gfxVars::FetchNonDefaultVars();
     74  if (!aUtilityParent->SendStartUtilityMediaService(
     75          std::move(utilityMediaServiceParentEnd), std::move(updates))) {
     76    MOZ_ASSERT(false, "StartUtilityMediaService service failure");
     77    return NS_ERROR_FAILURE;
     78  }
     79 
     80  Bind(std::move(utilityMediaServiceChildEnd));
     81 
     82  PROFILER_MARKER_UNTYPED("UtilityMediaServiceChild::BindToUtilityProcess", IPC,
     83                          MarkerOptions(MarkerTiming::IntervalUntilNowFrom(
     84                              mAudioDecoderChildStart)));
     85  return NS_OK;
     86 }
     87 
     88 void UtilityMediaServiceChild::ActorDestroy(ActorDestroyReason aReason) {
     89  MOZ_ASSERT(NS_IsMainThread());
     90  gfx::gfxVars::RemoveReceiver(this);
     91 #ifdef MOZ_WMF_MEDIA_ENGINE
     92  mHasCreatedVideoBridge = State::None;
     93  if (auto* gpm = gfx::GPUProcessManager::Get()) {
     94    // Note: the manager could have shutdown already.
     95    gpm->RemoveListener(this);
     96  }
     97 #endif
     98  Shutdown(mSandbox);
     99 }
    100 
    101 void UtilityMediaServiceChild::Bind(
    102    Endpoint<PUtilityMediaServiceChild>&& aEndpoint) {
    103  MOZ_ASSERT(NS_IsMainThread());
    104  if (NS_WARN_IF(!aEndpoint.Bind(this))) {
    105    MOZ_ASSERT_UNREACHABLE("Failed to bind UtilityMediaServiceChild!");
    106    return;
    107  }
    108  gfx::gfxVars::AddReceiver(this);
    109 }
    110 
    111 /* static */
    112 void UtilityMediaServiceChild::Shutdown(SandboxingKind aKind) {
    113  sAudioDecoderChilds[aKind] = nullptr;
    114 }
    115 
    116 /* static */
    117 RefPtr<UtilityMediaServiceChild> UtilityMediaServiceChild::GetSingleton(
    118    SandboxingKind aKind) {
    119  MOZ_ASSERT(NS_IsMainThread());
    120  bool shutdown = AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMWillShutdown);
    121  if (!sAudioDecoderChilds[aKind] && !shutdown) {
    122    sAudioDecoderChilds[aKind] = new UtilityMediaServiceChild(aKind);
    123  }
    124  return sAudioDecoderChilds[aKind];
    125 }
    126 
    127 mozilla::ipc::IPCResult
    128 UtilityMediaServiceChild::RecvUpdateMediaCodecsSupported(
    129    const RemoteMediaIn& aLocation,
    130    const media::MediaCodecsSupported& aSupported) {
    131  dom::ContentParent::BroadcastMediaCodecsSupportedUpdate(aLocation,
    132                                                          aSupported);
    133  return IPC_OK();
    134 }
    135 
    136 void UtilityMediaServiceChild::OnVarChanged(
    137    const nsTArray<gfx::GfxVarUpdate>& aVar) {
    138  SendUpdateVar(aVar);
    139 }
    140 
    141 #ifdef MOZ_WMF_MEDIA_ENGINE
    142 mozilla::ipc::IPCResult
    143 UtilityMediaServiceChild::RecvCompleteCreatedVideoBridge() {
    144  MOZ_ASSERT(NS_IsMainThread());
    145  MOZ_ASSERT(mSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM);
    146  if (mHasCreatedVideoBridge == State::Creating) {
    147    mHasCreatedVideoBridge = State::Created;
    148  } else {
    149    MOZ_ASSERT_UNREACHABLE("Video bridge created but was not creating?");
    150  }
    151  return IPC_OK();
    152 }
    153 
    154 void UtilityMediaServiceChild::OnCompositorUnexpectedShutdown() {
    155  MOZ_ASSERT(NS_IsMainThread());
    156  MOZ_ASSERT(mSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM);
    157  mHasCreatedVideoBridge = State::None;
    158 
    159  if (auto* gpm = gfx::GPUProcessManager::Get()) {
    160    if (auto utilpm = UtilityProcessManager::GetSingleton())
    161      if (auto parent = utilpm->GetProcessParent(mSandbox)) {
    162        if (NS_SUCCEEDED(gpm->CreateUtilityMFCDMVideoBridge(
    163                this, parent->OtherEndpointProcInfo()))) {
    164          mHasCreatedVideoBridge = State::Creating;
    165        }
    166      }
    167  }
    168 }
    169 
    170 bool UtilityMediaServiceChild::CreateVideoBridge(
    171    mozilla::ipc::EndpointProcInfo aOtherProcess) {
    172  MOZ_ASSERT(NS_IsMainThread());
    173  MOZ_ASSERT(mSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM);
    174 
    175  // Creating or already created, avoiding reinit a bridge.
    176  if (mHasCreatedVideoBridge != State::None) {
    177    return true;
    178  }
    179 
    180  auto* gpm = gfx::GPUProcessManager::Get();
    181  if (NS_WARN_IF(!gpm) || NS_WARN_IF(NS_FAILED(gpm->EnsureGPUReady())) ||
    182      NS_WARN_IF(
    183          NS_FAILED(gpm->CreateUtilityMFCDMVideoBridge(this, aOtherProcess)))) {
    184    return false;
    185  }
    186 
    187  gpm->AddListener(this);
    188  mHasCreatedVideoBridge = State::Creating;
    189  return true;
    190 }
    191 #endif
    192 
    193 #ifdef MOZ_WMF_CDM
    194 void UtilityMediaServiceChild::GetKeySystemCapabilities(
    195    dom::Promise* aPromise) {
    196  EME_LOG("Ask capabilities for all supported CDMs");
    197  SendGetKeySystemCapabilities()->Then(
    198      NS_GetCurrentThread(), __func__,
    199      [promise = RefPtr<dom::Promise>(aPromise)](
    200          CopyableTArray<MFCDMCapabilitiesIPDL>&& result) {
    201        FallibleTArray<dom::CDMInformation> cdmInfo;
    202        for (const auto& capabilities : result) {
    203          EME_LOG("Received capabilities for %s",
    204                  NS_ConvertUTF16toUTF8(capabilities.keySystem()).get());
    205          for (const auto& v : capabilities.videoCapabilities()) {
    206            for (const auto& scheme : v.encryptionSchemes()) {
    207              EME_LOG("  capabilities: video=%s, scheme=%s",
    208                      NS_ConvertUTF16toUTF8(v.contentType()).get(),
    209                      EnumValueToString(scheme));
    210            }
    211          }
    212          for (const auto& a : capabilities.audioCapabilities()) {
    213            for (const auto& scheme : a.encryptionSchemes()) {
    214              EME_LOG("  capabilities: audio=%s, scheme=%s",
    215                      NS_ConvertUTF16toUTF8(a.contentType()).get(),
    216                      EnumValueToString(scheme));
    217            }
    218          }
    219          auto* info = cdmInfo.AppendElement(fallible);
    220          if (!info) {
    221            promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
    222            return;
    223          }
    224          info->mKeySystemName = capabilities.keySystem();
    225 
    226          KeySystemConfig config;
    227          MFCDMCapabilitiesIPDLToKeySystemConfig(capabilities, config);
    228          info->mCapabilities = config.GetDebugInfo();
    229          info->mClearlead =
    230              DoesKeySystemSupportClearLead(info->mKeySystemName);
    231          if (capabilities.isHardwareDecryption()) {
    232            info->mIsHardwareDecryption = true;
    233          }
    234        }
    235        promise->MaybeResolve(cdmInfo);
    236      },
    237      [promise = RefPtr<dom::Promise>(aPromise)](
    238          const mozilla::ipc::ResponseRejectReason& aReason) {
    239        EME_LOG("IPC failure for GetKeySystemCapabilities!");
    240        promise->MaybeReject(NS_ERROR_DOM_MEDIA_CDM_ERR);
    241      });
    242 }
    243 
    244 mozilla::ipc::IPCResult UtilityMediaServiceChild::RecvDisableHardwareDRM() {
    245  MOZ_ASSERT(NS_IsMainThread());
    246  static constexpr const char* kHardDRMPref = "media.eme.hwdrm.failed";
    247  Preferences::SetBool(kHardDRMPref, true);
    248  return IPC_OK();
    249 }
    250 #endif
    251 
    252 }  // namespace mozilla::ipc