tor-browser

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

RemoteMediaManagerChild.cpp (48697B)


      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
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 #include "RemoteMediaManagerChild.h"
      7 
      8 #include "EMEDecoderModule.h"
      9 #include "ErrorList.h"
     10 #include "MP4Decoder.h"
     11 #include "PDMFactory.h"
     12 #include "PEMFactory.h"
     13 #include "PlatformDecoderModule.h"
     14 #include "PlatformEncoderModule.h"
     15 #include "RemoteAudioDecoder.h"
     16 #include "RemoteCDMChild.h"
     17 #include "RemoteMediaDataDecoder.h"
     18 #include "RemoteMediaDataEncoderChild.h"
     19 #include "RemoteVideoDecoder.h"
     20 #include "VideoUtils.h"
     21 #include "mozilla/DataMutex.h"
     22 #include "mozilla/MozPromise.h"
     23 #include "mozilla/RemoteDecodeUtils.h"
     24 #include "mozilla/StaticPrefs_media.h"
     25 #include "mozilla/StaticPtr.h"
     26 #include "mozilla/SyncRunnable.h"
     27 #include "mozilla/dom/ContentChild.h"  // for launching RDD w/ ContentChild
     28 #include "mozilla/gfx/2D.h"
     29 #include "mozilla/gfx/DataSurfaceHelpers.h"
     30 #include "mozilla/ipc/BackgroundChild.h"
     31 #include "mozilla/ipc/Endpoint.h"
     32 #include "mozilla/ipc/PBackgroundChild.h"
     33 #include "mozilla/ipc/UtilityMediaServiceChild.h"
     34 #include "mozilla/layers/ISurfaceAllocator.h"
     35 #include "nsContentUtils.h"
     36 #include "nsIObserver.h"
     37 #include "nsPrintfCString.h"
     38 
     39 #ifdef MOZ_WMF_MEDIA_ENGINE
     40 #  include "MFMediaEngineChild.h"
     41 #endif
     42 
     43 #ifdef MOZ_WMF_CDM
     44 #  include "MFCDMChild.h"
     45 #endif
     46 
     47 namespace mozilla {
     48 
     49 #define LOG(msg, ...) \
     50  MOZ_LOG(gRemoteDecodeLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
     51 
     52 using namespace layers;
     53 using namespace gfx;
     54 
     55 using media::EncodeSupport;
     56 using media::EncodeSupportSet;
     57 
     58 // Used so that we only ever attempt to check if the RDD/GPU/Utility processes
     59 // should be launched serially. Protects sLaunchPromise
     60 StaticMutex sLaunchMutex;
     61 static EnumeratedArray<RemoteMediaIn, StaticRefPtr<GenericNonExclusivePromise>,
     62                       size_t(RemoteMediaIn::SENTINEL)>
     63    sLaunchPromises MOZ_GUARDED_BY(sLaunchMutex);
     64 
     65 // Only modified on the main-thread, read on any thread. While it could be read
     66 // on the main thread directly, for clarity we force access via the DataMutex
     67 // wrapper.
     68 MOZ_RUNINIT static StaticDataMutex<StaticRefPtr<nsIThread>>
     69    sRemoteMediaManagerChildThread("sRemoteMediaManagerChildThread");
     70 
     71 // Only accessed from sRemoteMediaManagerChildThread
     72 static EnumeratedArray<RemoteMediaIn, StaticRefPtr<RemoteMediaManagerChild>,
     73                       size_t(RemoteMediaIn::SENTINEL)>
     74    sRemoteMediaManagerChildForProcesses;
     75 
     76 static StaticAutoPtr<nsTArray<RefPtr<Runnable>>> sRecreateTasks;
     77 
     78 // Used for protecting codec support information collected from different remote
     79 // processes.
     80 StaticMutex sProcessSupportedMutex;
     81 MOZ_GLOBINIT static EnumeratedArray<RemoteMediaIn,
     82                                    Maybe<media::MediaCodecsSupported>,
     83                                    size_t(RemoteMediaIn::SENTINEL)>
     84    sProcessSupported MOZ_GUARDED_BY(sProcessSupportedMutex);
     85 
     86 class ShutdownObserver final : public nsIObserver {
     87 public:
     88  NS_DECL_ISUPPORTS
     89  NS_DECL_NSIOBSERVER
     90 
     91 protected:
     92  ~ShutdownObserver() = default;
     93 };
     94 NS_IMPL_ISUPPORTS(ShutdownObserver, nsIObserver);
     95 
     96 NS_IMETHODIMP
     97 ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
     98                          const char16_t* aData) {
     99  MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID));
    100  RemoteMediaManagerChild::Shutdown();
    101  return NS_OK;
    102 }
    103 
    104 StaticRefPtr<ShutdownObserver> sObserver;
    105 
    106 /* static */
    107 void RemoteMediaManagerChild::Init() {
    108  LOG("RemoteMediaManagerChild Init");
    109 
    110  auto remoteDecoderManagerThread = sRemoteMediaManagerChildThread.Lock();
    111  if (!*remoteDecoderManagerThread) {
    112    LOG("RemoteMediaManagerChild's thread is created");
    113    // We can't use a MediaThreadType::SUPERVISOR as the RemoteDecoderModule
    114    // runs on it and dispatch synchronous tasks to the manager thread, should
    115    // more than 4 concurrent videos being instantiated at the same time, we
    116    // could end up in a deadlock.
    117    RefPtr<nsIThread> childThread;
    118    nsresult rv = NS_NewNamedThread(
    119        "RemVidChild", getter_AddRefs(childThread),
    120        NS_NewRunnableFunction(
    121            "RemoteMediaManagerChild::InitPBackground", []() {
    122              ipc::PBackgroundChild* bgActor =
    123                  ipc::BackgroundChild::GetOrCreateForCurrentThread();
    124              NS_WARNING_ASSERTION(bgActor,
    125                                   "Failed to start Background channel");
    126              (void)bgActor;
    127            }));
    128 
    129    NS_ENSURE_SUCCESS_VOID(rv);
    130    *remoteDecoderManagerThread = childThread;
    131    sRecreateTasks = new nsTArray<RefPtr<Runnable>>();
    132    sObserver = new ShutdownObserver();
    133    nsContentUtils::RegisterShutdownObserver(sObserver);
    134  }
    135 }
    136 
    137 /* static */
    138 void RemoteMediaManagerChild::InitForGPUProcess(
    139    Endpoint<PRemoteMediaManagerChild>&& aVideoManager) {
    140  MOZ_ASSERT(NS_IsMainThread());
    141 
    142  Init();
    143 
    144  auto remoteDecoderManagerThread = sRemoteMediaManagerChildThread.Lock();
    145  MOZ_ALWAYS_SUCCEEDS(
    146      (*remoteDecoderManagerThread)
    147          ->Dispatch(NewRunnableFunction(
    148              "InitForContentRunnable", &OpenRemoteMediaManagerChildForProcess,
    149              std::move(aVideoManager), RemoteMediaIn::GpuProcess)));
    150 }
    151 
    152 /* static */
    153 void RemoteMediaManagerChild::Shutdown() {
    154  MOZ_ASSERT(NS_IsMainThread());
    155  LOG("RemoteMediaManagerChild Shutdown");
    156 
    157  if (sObserver) {
    158    nsContentUtils::UnregisterShutdownObserver(sObserver);
    159    sObserver = nullptr;
    160  }
    161 
    162  nsCOMPtr<nsIThread> childThread;
    163  {
    164    auto remoteDecoderManagerThread = sRemoteMediaManagerChildThread.Lock();
    165    childThread = remoteDecoderManagerThread->forget();
    166    LOG("RemoteMediaManagerChild's thread is released");
    167  }
    168  if (childThread) {
    169    MOZ_ALWAYS_SUCCEEDS(childThread->Dispatch(
    170        NS_NewRunnableFunction("dom::RemoteMediaManagerChild::Shutdown", []() {
    171          for (auto& p : sRemoteMediaManagerChildForProcesses) {
    172            if (p && p->CanSend()) {
    173              p->Close();
    174            }
    175            p = nullptr;
    176          }
    177          {
    178            StaticMutexAutoLock lock(sLaunchMutex);
    179            for (auto& p : sLaunchPromises) {
    180              p = nullptr;
    181            }
    182          }
    183          ipc::BackgroundChild::CloseForCurrentThread();
    184        })));
    185    childThread->Shutdown();
    186    sRecreateTasks = nullptr;
    187  }
    188 }
    189 
    190 /* static */ void RemoteMediaManagerChild::RunWhenGPUProcessRecreated(
    191    const RemoteMediaManagerChild* aDyingManager,
    192    already_AddRefed<Runnable> aTask) {
    193  nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
    194  if (!managerThread) {
    195    // We've been shutdown, bail.
    196    return;
    197  }
    198  MOZ_ASSERT(managerThread->IsOnCurrentThread());
    199 
    200  // If we've already been recreated, then run the task immediately.
    201  auto* manager = GetSingleton(RemoteMediaIn::GpuProcess);
    202  if (manager && manager != aDyingManager && manager->CanSend()) {
    203    RefPtr<Runnable> task = aTask;
    204    task->Run();
    205  } else {
    206    sRecreateTasks->AppendElement(aTask);
    207  }
    208 }
    209 
    210 /* static */
    211 RemoteMediaManagerChild* RemoteMediaManagerChild::GetSingleton(
    212    RemoteMediaIn aLocation) {
    213  nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
    214  if (!managerThread) {
    215    // We've been shutdown, bail.
    216    return nullptr;
    217  }
    218  MOZ_ASSERT(managerThread->IsOnCurrentThread());
    219  switch (aLocation) {
    220    case RemoteMediaIn::GpuProcess:
    221    case RemoteMediaIn::RddProcess:
    222    case RemoteMediaIn::UtilityProcess_Generic:
    223    case RemoteMediaIn::UtilityProcess_AppleMedia:
    224    case RemoteMediaIn::UtilityProcess_WMF:
    225    case RemoteMediaIn::UtilityProcess_MFMediaEngineCDM:
    226      return sRemoteMediaManagerChildForProcesses[aLocation];
    227    default:
    228      MOZ_CRASH("Unexpected RemoteMediaIn variant");
    229      return nullptr;
    230  }
    231 }
    232 
    233 /* static */
    234 nsCOMPtr<nsISerialEventTarget> RemoteMediaManagerChild::GetManagerThread() {
    235  auto remoteDecoderManagerThread = sRemoteMediaManagerChildThread.Lock();
    236  return nsCOMPtr<nsISerialEventTarget>(*remoteDecoderManagerThread);
    237 }
    238 
    239 /* static */
    240 bool RemoteMediaManagerChild::Supports(RemoteMediaIn aLocation,
    241                                       const SupportDecoderParams& aParams,
    242                                       DecoderDoctorDiagnostics* aDiagnostics) {
    243  Maybe<media::MediaCodecsSupported> supported;
    244  switch (aLocation) {
    245    case RemoteMediaIn::GpuProcess:
    246    case RemoteMediaIn::RddProcess:
    247    case RemoteMediaIn::UtilityProcess_AppleMedia:
    248    case RemoteMediaIn::UtilityProcess_Generic:
    249    case RemoteMediaIn::UtilityProcess_WMF:
    250    case RemoteMediaIn::UtilityProcess_MFMediaEngineCDM: {
    251      StaticMutexAutoLock lock(sProcessSupportedMutex);
    252      supported = sProcessSupported[aLocation];
    253      break;
    254    }
    255    default:
    256      return false;
    257  }
    258  if (!supported) {
    259    // We haven't received the correct information yet from either the GPU or
    260    // the RDD process nor the Utility process.
    261    if (aLocation == RemoteMediaIn::UtilityProcess_Generic ||
    262        aLocation == RemoteMediaIn::UtilityProcess_AppleMedia ||
    263        aLocation == RemoteMediaIn::UtilityProcess_WMF ||
    264        aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) {
    265      LaunchUtilityProcessIfNeeded(aLocation);
    266    }
    267    if (aLocation == RemoteMediaIn::RddProcess) {
    268      // Ensure the RDD process got started.
    269      // TODO: This can be removed once bug 1684991 is fixed.
    270      LaunchRDDProcessIfNeeded();
    271    }
    272 
    273    // Assume the format is supported to prevent false negative, if the remote
    274    // process supports that specific track type.
    275    const bool isVideo = aParams.mConfig.IsVideo();
    276    const bool isAudio = aParams.mConfig.IsAudio();
    277    const auto trackSupport = GetTrackSupport(aLocation);
    278    if (isVideo) {
    279      // Special condition for HEVC, which can only be supported in specific
    280      // process. As HEVC support is still a experimental feature, we don't want
    281      // to report support for it arbitrarily.
    282      if (MP4Decoder::IsHEVC(aParams.mConfig.mMimeType)) {
    283        if (!StaticPrefs::media_hevc_enabled()) {
    284          return false;
    285        }
    286 #if defined(XP_WIN)
    287        return aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM ||
    288               aLocation == RemoteMediaIn::GpuProcess;
    289 #else
    290        return trackSupport.contains(TrackSupport::DecodeVideo);
    291 #endif
    292      }
    293      return trackSupport.contains(TrackSupport::DecodeVideo);
    294    }
    295    if (isAudio) {
    296      return trackSupport.contains(TrackSupport::DecodeAudio);
    297    }
    298    MOZ_ASSERT_UNREACHABLE("Not audio and video?!");
    299    return false;
    300  }
    301 
    302  // We can ignore the SupportDecoderParams argument for now as creation of the
    303  // decoder will actually fail later and fallback PDMs will be tested on later.
    304  return !PDMFactory::SupportsMimeType(aParams.MimeType(), *supported,
    305                                       aLocation)
    306              .isEmpty();
    307 }
    308 
    309 /* static */
    310 RefPtr<PlatformDecoderModule::CreateDecoderPromise>
    311 RemoteMediaManagerChild::CreateAudioDecoder(const CreateDecoderParams& aParams,
    312                                            RemoteMediaIn aLocation) {
    313  nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
    314  if (!managerThread) {
    315    // We got shutdown.
    316    return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
    317        NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    318  }
    319 
    320  if (!GetTrackSupport(aLocation).contains(TrackSupport::DecodeAudio)) {
    321    return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
    322        MediaResult(NS_ERROR_DOM_MEDIA_CANCELED,
    323                    nsPrintfCString("%s doesn't support audio decoding",
    324                                    RemoteMediaInToStr(aLocation))
    325                        .get()),
    326        __func__);
    327  }
    328 
    329  if (!aParams.mMediaEngineId &&
    330      aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) {
    331    return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
    332        MediaResult(NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR,
    333                    nsPrintfCString("%s only support for media engine playback",
    334                                    RemoteMediaInToStr(aLocation))
    335                        .get()),
    336        __func__);
    337  }
    338 
    339  RefPtr<GenericNonExclusivePromise> launchPromise;
    340  if (StaticPrefs::media_utility_process_enabled() &&
    341      (aLocation == RemoteMediaIn::UtilityProcess_Generic ||
    342       aLocation == RemoteMediaIn::UtilityProcess_AppleMedia ||
    343       aLocation == RemoteMediaIn::UtilityProcess_WMF)) {
    344    launchPromise = LaunchUtilityProcessIfNeeded(aLocation);
    345  } else if (aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) {
    346    launchPromise = LaunchUtilityProcessIfNeeded(aLocation);
    347  } else if (StaticPrefs::media_allow_audio_non_utility() || aParams.mCDM) {
    348    launchPromise = LaunchRDDProcessIfNeeded();
    349  } else {
    350    return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
    351        MediaResult(
    352            NS_ERROR_DOM_MEDIA_DENIED_IN_NON_UTILITY,
    353            nsPrintfCString("%s is not allowed to perform audio decoding",
    354                            RemoteMediaInToStr(aLocation))
    355                .get()),
    356        __func__);
    357  }
    358  LOG("Create audio decoder in %s", RemoteMediaInToStr(aLocation));
    359 
    360  return launchPromise->Then(
    361      managerThread, __func__,
    362      [params = CreateDecoderParamsForAsync(aParams), aLocation](bool) mutable {
    363        auto child = MakeRefPtr<RemoteAudioDecoderChild>(aLocation);
    364        MediaResult result =
    365            child->InitIPDL(params.AudioConfig(), params.mOptions,
    366                            params.mMediaEngineId, params.mCDM);
    367        if (NS_FAILED(result)) {
    368          return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
    369              result, __func__);
    370        }
    371        return Construct(std::move(child), std::move(params), aLocation);
    372      },
    373      [aLocation](nsresult aResult) {
    374        return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
    375            MediaResult(aResult,
    376                        aLocation == RemoteMediaIn::GpuProcess
    377                            ? "Couldn't start GPU process"
    378                            : (aLocation == RemoteMediaIn::RddProcess
    379                                   ? "Couldn't start RDD process"
    380                                   : "Couldn't start Utility process")),
    381            __func__);
    382      });
    383 }
    384 
    385 /* static */
    386 RefPtr<PlatformDecoderModule::CreateDecoderPromise>
    387 RemoteMediaManagerChild::CreateVideoDecoder(const CreateDecoderParams& aParams,
    388                                            RemoteMediaIn aLocation) {
    389  nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
    390  if (!managerThread) {
    391    // We got shutdown.
    392    return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
    393        NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    394  }
    395 
    396  if (!aParams.mKnowsCompositor && aLocation == RemoteMediaIn::GpuProcess) {
    397    // We don't have an image bridge; don't attempt to decode in the GPU
    398    // process.
    399    return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
    400        NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR, __func__);
    401  }
    402 
    403  if (!GetTrackSupport(aLocation).contains(TrackSupport::DecodeVideo)) {
    404    return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
    405        MediaResult(NS_ERROR_DOM_MEDIA_CANCELED,
    406                    nsPrintfCString("%s doesn't support video decoding",
    407                                    RemoteMediaInToStr(aLocation))
    408                        .get()),
    409        __func__);
    410  }
    411 
    412  if (!aParams.mMediaEngineId &&
    413      aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) {
    414    return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
    415        MediaResult(NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR,
    416                    nsPrintfCString("%s only support for media engine playback",
    417                                    RemoteMediaInToStr(aLocation))
    418                        .get()),
    419        __func__);
    420  }
    421 
    422  MOZ_ASSERT(aLocation != RemoteMediaIn::Unspecified);
    423 
    424  RefPtr<GenericNonExclusivePromise> p;
    425  if (aLocation == RemoteMediaIn::GpuProcess) {
    426    p = GenericNonExclusivePromise::CreateAndResolve(true, __func__);
    427  } else if (aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) {
    428    p = LaunchUtilityProcessIfNeeded(aLocation);
    429  } else {
    430    p = LaunchRDDProcessIfNeeded();
    431  }
    432  LOG("Create video decoder in %s", RemoteMediaInToStr(aLocation));
    433 
    434  return p->Then(
    435      managerThread, __func__,
    436      [aLocation, params = CreateDecoderParamsForAsync(aParams)](bool) mutable {
    437        auto child = MakeRefPtr<RemoteVideoDecoderChild>(aLocation);
    438        MediaResult result = child->InitIPDL(
    439            params.VideoConfig(), params.mRate.mValue, params.mOptions,
    440            params.mKnowsCompositor
    441                ? Some(params.mKnowsCompositor->GetTextureFactoryIdentifier())
    442                : Nothing(),
    443            params.mMediaEngineId, params.mTrackingId, params.mCDM);
    444        if (NS_FAILED(result)) {
    445          return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
    446              result, __func__);
    447        }
    448        return Construct(std::move(child), std::move(params), aLocation);
    449      },
    450      [](nsresult aResult) {
    451        return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
    452            MediaResult(aResult, "Couldn't start RDD process"), __func__);
    453      });
    454 }
    455 
    456 /* static */
    457 RefPtr<RemoteCDMChild> RemoteMediaManagerChild::CreateCDM(
    458    RemoteMediaIn aLocation, dom::MediaKeys* aKeys, const nsAString& aKeySystem,
    459    bool aDistinctiveIdentifierRequired, bool aPersistentStateRequired) {
    460  MOZ_ASSERT(NS_IsMainThread());
    461 
    462  if (NS_WARN_IF(aLocation != RemoteMediaIn::RddProcess)) {
    463    MOZ_ASSERT_UNREACHABLE("Cannot use CDM outside RDD process");
    464    return nullptr;
    465  }
    466 
    467  if (!StaticPrefs::media_ffvpx_hw_enabled()) {
    468    return nullptr;
    469  }
    470 
    471  nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
    472  if (!managerThread) {
    473    // We got shutdown.
    474    return nullptr;
    475  }
    476 
    477  if (!GetTrackSupport(aLocation).contains(TrackSupport::DecodeVideo)) {
    478    return nullptr;
    479  }
    480 
    481  RefPtr<GenericNonExclusivePromise> p = LaunchRDDProcessIfNeeded();
    482  LOG("Create CDM in %s", RemoteMediaInToStr(aLocation));
    483 
    484  return MakeRefPtr<RemoteCDMChild>(
    485      std::move(managerThread), std::move(p), aLocation, aKeys, aKeySystem,
    486      aDistinctiveIdentifierRequired, aPersistentStateRequired);
    487 }
    488 
    489 /* static */
    490 RefPtr<PlatformDecoderModule::CreateDecoderPromise>
    491 RemoteMediaManagerChild::Construct(RefPtr<RemoteDecoderChild>&& aChild,
    492                                   CreateDecoderParamsForAsync&& aParams,
    493                                   RemoteMediaIn aLocation) {
    494  nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
    495  if (!managerThread) {
    496    // We got shutdown.
    497    return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
    498        NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    499  }
    500  MOZ_ASSERT(managerThread->IsOnCurrentThread());
    501 
    502  RefPtr<PlatformDecoderModule::CreateDecoderPromise> p =
    503      aChild->SendConstruct()->Then(
    504          managerThread, __func__,
    505          [child = std::move(aChild),
    506           params = std::move(aParams)](MediaResult aResult) {
    507            if (NS_FAILED(aResult)) {
    508              // We will never get to use this remote decoder, tear it down.
    509              child->DestroyIPDL();
    510              return PlatformDecoderModule::CreateDecoderPromise::
    511                  CreateAndReject(aResult, __func__);
    512            }
    513            if (params.mCDM) {
    514              if (auto* cdmChild = params.mCDM->AsPRemoteCDMChild()) {
    515                return PlatformDecoderModule::CreateDecoderPromise::
    516                    CreateAndResolve(
    517                        MakeRefPtr<EMEMediaDataDecoderProxy>(
    518                            params,
    519                            MakeAndAddRef<RemoteMediaDataDecoder>(child),
    520                            static_cast<RemoteCDMChild*>(cdmChild)),
    521                        __func__);
    522              }
    523              return PlatformDecoderModule::CreateDecoderPromise::
    524                  CreateAndReject(
    525                      NS_ERROR_DOM_MEDIA_CDM_PROXY_NOT_SUPPORTED_ERR, __func__);
    526            }
    527            return PlatformDecoderModule::CreateDecoderPromise::
    528                CreateAndResolve(MakeRefPtr<RemoteMediaDataDecoder>(child),
    529                                 __func__);
    530          },
    531          [aLocation](const mozilla::ipc::ResponseRejectReason& aReason) {
    532            // The parent has died.
    533            nsresult err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_UTILITY_ERR;
    534            if (aLocation == RemoteMediaIn::GpuProcess ||
    535                aLocation == RemoteMediaIn::RddProcess) {
    536              err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_RDD_OR_GPU_ERR;
    537            } else if (aLocation ==
    538                       RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) {
    539              err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_MF_CDM_ERR;
    540            }
    541            return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
    542                err, __func__);
    543          });
    544  return p;
    545 }
    546 
    547 /* static */
    548 EncodeSupportSet RemoteMediaManagerChild::Supports(RemoteMediaIn aLocation,
    549                                                   CodecType aCodec) {
    550  Maybe<media::MediaCodecsSupported> supported;
    551  switch (aLocation) {
    552    case RemoteMediaIn::GpuProcess:
    553    case RemoteMediaIn::RddProcess:
    554    case RemoteMediaIn::UtilityProcess_AppleMedia:
    555    case RemoteMediaIn::UtilityProcess_Generic:
    556    case RemoteMediaIn::UtilityProcess_WMF:
    557    case RemoteMediaIn::UtilityProcess_MFMediaEngineCDM: {
    558      StaticMutexAutoLock lock(sProcessSupportedMutex);
    559      supported = sProcessSupported[aLocation];
    560      break;
    561    }
    562    default:
    563      return EncodeSupportSet{};
    564  }
    565  if (!supported) {
    566    // We haven't received the correct information yet from either the GPU or
    567    // the RDD process nor the Utility process.
    568    if (aLocation == RemoteMediaIn::UtilityProcess_Generic ||
    569        aLocation == RemoteMediaIn::UtilityProcess_AppleMedia ||
    570        aLocation == RemoteMediaIn::UtilityProcess_WMF ||
    571        aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) {
    572      LaunchUtilityProcessIfNeeded(aLocation);
    573    }
    574    if (aLocation == RemoteMediaIn::RddProcess) {
    575      // Ensure the RDD process got started.
    576      // TODO: This can be removed once bug 1684991 is fixed.
    577      LaunchRDDProcessIfNeeded();
    578    }
    579 
    580    // Assume the format is supported to prevent false negative, if the remote
    581    // process supports that specific track type.
    582    const auto trackSupport = GetTrackSupport(aLocation);
    583    if (IsVideo(aCodec)) {
    584      // Special condition for HEVC, which can only be supported in specific
    585      // process. As HEVC support is still a experimental feature, we don't want
    586      // to report support for it arbitrarily.
    587      bool supported = trackSupport.contains(TrackSupport::EncodeVideo);
    588      if (aCodec == CodecType::H265) {
    589        if (!StaticPrefs::media_hevc_enabled()) {
    590          return EncodeSupportSet{};
    591        }
    592 #if defined(XP_WIN)
    593        supported = aLocation == RemoteMediaIn::GpuProcess;
    594 #endif
    595      }
    596      return supported ? EncodeSupportSet{EncodeSupport::SoftwareEncode}
    597                       : EncodeSupportSet{};
    598    }
    599    if (IsAudio(aCodec)) {
    600      return trackSupport.contains(TrackSupport::EncodeAudio)
    601                 ? EncodeSupportSet{EncodeSupport::SoftwareEncode}
    602                 : EncodeSupportSet{};
    603    }
    604    MOZ_ASSERT_UNREACHABLE("Not audio and video?!");
    605    return EncodeSupportSet{};
    606  }
    607 
    608  // We can ignore the rest of EncoderConfig for now as creation of the encoder
    609  // will actually fail later and fallback PEMs will be tested on later.
    610  return PEMFactory::SupportsCodec(aCodec, *supported, aLocation);
    611 }
    612 
    613 /* static */ RefPtr<PlatformEncoderModule::CreateEncoderPromise>
    614 RemoteMediaManagerChild::InitializeEncoder(
    615    RefPtr<RemoteMediaDataEncoderChild>&& aEncoder,
    616    const EncoderConfig& aConfig) {
    617  RemoteMediaIn location = aEncoder->GetLocation();
    618 
    619  TrackSupport required;
    620  if (aConfig.IsAudio()) {
    621    required = TrackSupport::EncodeAudio;
    622  } else if (aConfig.IsVideo()) {
    623    required = TrackSupport::EncodeVideo;
    624  } else {
    625    return PlatformEncoderModule::CreateEncoderPromise::CreateAndReject(
    626        MediaResult(NS_ERROR_DOM_MEDIA_CANCELED,
    627                    nsPrintfCString("%s doesn't support encoding",
    628                                    RemoteMediaInToStr(location))
    629                        .get()),
    630        __func__);
    631  }
    632 
    633  if (!GetTrackSupport(location).contains(required)) {
    634    return PlatformEncoderModule::CreateEncoderPromise::CreateAndReject(
    635        MediaResult(NS_ERROR_DOM_MEDIA_CANCELED,
    636                    nsPrintfCString("%s doesn't support encoding",
    637                                    RemoteMediaInToStr(location))
    638                        .get()),
    639        __func__);
    640  }
    641 
    642  auto managerThread = aEncoder->GetManagerThread();
    643  if (!managerThread) {
    644    return PlatformEncoderModule::CreateEncoderPromise::CreateAndReject(
    645        MediaResult(NS_ERROR_DOM_MEDIA_CANCELED, "Thread shutdown"_ns),
    646        __func__);
    647  }
    648 
    649  MOZ_ASSERT(location != RemoteMediaIn::Unspecified);
    650 
    651  RefPtr<GenericNonExclusivePromise> p;
    652  if (location == RemoteMediaIn::UtilityProcess_Generic ||
    653      location == RemoteMediaIn::UtilityProcess_AppleMedia ||
    654      location == RemoteMediaIn::UtilityProcess_WMF) {
    655    p = LaunchUtilityProcessIfNeeded(location);
    656  } else if (location == RemoteMediaIn::GpuProcess) {
    657    p = GenericNonExclusivePromise::CreateAndResolve(true, __func__);
    658  } else if (location == RemoteMediaIn::RddProcess) {
    659    p = LaunchRDDProcessIfNeeded();
    660  } else {
    661    p = GenericNonExclusivePromise::CreateAndReject(
    662        NS_ERROR_DOM_MEDIA_DENIED_IN_NON_UTILITY, __func__);
    663  }
    664  LOG("Creating %s encoder type %d in %s",
    665      aConfig.IsAudio() ? "audio" : "video", static_cast<int>(aConfig.mCodec),
    666      RemoteMediaInToStr(location));
    667 
    668  return p->Then(
    669      managerThread, __func__,
    670      [encoder = std::move(aEncoder), aConfig](bool) {
    671        auto* manager = GetSingleton(encoder->GetLocation());
    672        if (!manager) {
    673          LOG("Create encoder in %s failed, shutdown",
    674              RemoteMediaInToStr(encoder->GetLocation()));
    675          // We got shutdown.
    676          return PlatformEncoderModule::CreateEncoderPromise::CreateAndReject(
    677              MediaResult(NS_ERROR_DOM_MEDIA_CANCELED,
    678                          "Remote manager not available"),
    679              __func__);
    680        }
    681        if (!manager->SendPRemoteEncoderConstructor(encoder, aConfig)) {
    682          LOG("Create encoder in %s failed, send failed",
    683              RemoteMediaInToStr(encoder->GetLocation()));
    684          return PlatformEncoderModule::CreateEncoderPromise::CreateAndReject(
    685              MediaResult(NS_ERROR_NOT_AVAILABLE,
    686                          "Failed to construct encoder actor"),
    687              __func__);
    688        }
    689        return encoder->Construct();
    690      },
    691      [location](nsresult aResult) {
    692        LOG("Create encoder in %s failed, cannot start process",
    693            RemoteMediaInToStr(location));
    694        return PlatformEncoderModule::CreateEncoderPromise::CreateAndReject(
    695            MediaResult(aResult, "Couldn't start encode process"), __func__);
    696      });
    697 }
    698 
    699 /* static */
    700 RefPtr<GenericNonExclusivePromise>
    701 RemoteMediaManagerChild::LaunchRDDProcessIfNeeded() {
    702  MOZ_DIAGNOSTIC_ASSERT(XRE_IsContentProcess(),
    703                        "Only supported from a content process.");
    704 
    705  nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
    706  if (!managerThread) {
    707    // We got shutdown.
    708    return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE,
    709                                                       __func__);
    710  }
    711 
    712  StaticMutexAutoLock lock(sLaunchMutex);
    713  auto& rddLaunchPromise = sLaunchPromises[RemoteMediaIn::RddProcess];
    714  if (rddLaunchPromise) {
    715    return rddLaunchPromise;
    716  }
    717 
    718  // We have a couple possible states here.  We are in a content process
    719  // and:
    720  // 1) the RDD process has never been launched.  RDD should be launched
    721  //    and the IPC connections setup.
    722  // 2) the RDD process has been launched, but this particular content
    723  //    process has not setup (or has lost) its IPC connection.
    724  // In the code below, we assume we need to launch the RDD process and
    725  // setup the IPC connections.  However, if the manager thread for
    726  // RemoteMediaManagerChild is available we do a quick check to see
    727  // if we can send (meaning the IPC channel is open).  If we can send,
    728  // then no work is necessary.  If we can't send, then we call
    729  // LaunchRDDProcess which will launch RDD if necessary, and setup the
    730  // IPC connections between *this* content process and the RDD process.
    731 
    732  RefPtr<GenericNonExclusivePromise> p = InvokeAsync(
    733      managerThread, __func__, []() -> RefPtr<GenericNonExclusivePromise> {
    734        auto* rps = GetSingleton(RemoteMediaIn::RddProcess);
    735        if (rps && rps->CanSend()) {
    736          return GenericNonExclusivePromise::CreateAndResolve(true, __func__);
    737        }
    738        nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
    739        ipc::PBackgroundChild* bgActor =
    740            ipc::BackgroundChild::GetForCurrentThread();
    741        if (!managerThread || NS_WARN_IF(!bgActor)) {
    742          return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE,
    743                                                             __func__);
    744        }
    745 
    746        return bgActor->SendEnsureRDDProcessAndCreateBridge()->Then(
    747            managerThread, __func__,
    748            [](ipc::PBackgroundChild::EnsureRDDProcessAndCreateBridgePromise::
    749                   ResolveOrRejectValue&& aResult) {
    750              nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
    751              if (!managerThread || aResult.IsReject()) {
    752                // The parent process died or we got shutdown
    753                return GenericNonExclusivePromise::CreateAndReject(
    754                    NS_ERROR_FAILURE, __func__);
    755              }
    756              nsresult rv = std::get<0>(aResult.ResolveValue());
    757              if (NS_FAILED(rv)) {
    758                return GenericNonExclusivePromise::CreateAndReject(rv,
    759                                                                   __func__);
    760              }
    761              OpenRemoteMediaManagerChildForProcess(
    762                  std::get<1>(std::move(aResult.ResolveValue())),
    763                  RemoteMediaIn::RddProcess);
    764              return GenericNonExclusivePromise::CreateAndResolve(true,
    765                                                                  __func__);
    766            });
    767      });
    768 
    769  // This should not be dispatched to a threadpool thread, so use managerThread
    770  p = p->Then(
    771      managerThread, __func__,
    772      [](const GenericNonExclusivePromise::ResolveOrRejectValue& aResult) {
    773        StaticMutexAutoLock lock(sLaunchMutex);
    774        sLaunchPromises[RemoteMediaIn::RddProcess] = nullptr;
    775        return GenericNonExclusivePromise::CreateAndResolveOrReject(aResult,
    776                                                                    __func__);
    777      });
    778 
    779  rddLaunchPromise = p;
    780  return rddLaunchPromise;
    781 }
    782 
    783 /* static */
    784 RefPtr<GenericNonExclusivePromise>
    785 RemoteMediaManagerChild::LaunchUtilityProcessIfNeeded(RemoteMediaIn aLocation) {
    786  MOZ_DIAGNOSTIC_ASSERT(XRE_IsContentProcess(),
    787                        "Only supported from a content process.");
    788 
    789  nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
    790  if (!managerThread) {
    791    // We got shutdown.
    792    return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE,
    793                                                       __func__);
    794  }
    795 
    796  MOZ_ASSERT(aLocation == RemoteMediaIn::UtilityProcess_Generic ||
    797             aLocation == RemoteMediaIn::UtilityProcess_AppleMedia ||
    798             aLocation == RemoteMediaIn::UtilityProcess_WMF ||
    799             aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM);
    800  StaticMutexAutoLock lock(sLaunchMutex);
    801  auto& utilityLaunchPromise = sLaunchPromises[aLocation];
    802 
    803  if (utilityLaunchPromise) {
    804    return utilityLaunchPromise;
    805  }
    806 
    807  // We have a couple possible states here.  We are in a content process
    808  // and:
    809  // 1) the Utility process has never been launched.  Utility should be launched
    810  //    and the IPC connections setup.
    811  // 2) the Utility process has been launched, but this particular content
    812  //    process has not setup (or has lost) its IPC connection.
    813  // In the code below, we assume we need to launch the Utility process and
    814  // setup the IPC connections.  However, if the manager thread for
    815  // RemoteMediaManagerChild is available we do a quick check to see
    816  // if we can send (meaning the IPC channel is open).  If we can send,
    817  // then no work is necessary.  If we can't send, then we call
    818  // LaunchUtilityProcess which will launch Utility if necessary, and setup the
    819  // IPC connections between *this* content process and the Utility process.
    820 
    821  RefPtr<GenericNonExclusivePromise> p = InvokeAsync(
    822      managerThread, __func__,
    823      [aLocation]() -> RefPtr<GenericNonExclusivePromise> {
    824        auto* rps = GetSingleton(aLocation);
    825        if (rps && rps->CanSend()) {
    826          return GenericNonExclusivePromise::CreateAndResolve(true, __func__);
    827        }
    828        nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
    829        ipc::PBackgroundChild* bgActor =
    830            ipc::BackgroundChild::GetForCurrentThread();
    831        if (!managerThread || NS_WARN_IF(!bgActor)) {
    832          return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE,
    833                                                             __func__);
    834        }
    835 
    836        return bgActor->SendEnsureUtilityProcessAndCreateBridge(aLocation)
    837            ->Then(managerThread, __func__,
    838                   [aLocation](ipc::PBackgroundChild::
    839                                   EnsureUtilityProcessAndCreateBridgePromise::
    840                                       ResolveOrRejectValue&& aResult)
    841                       -> RefPtr<GenericNonExclusivePromise> {
    842                     nsCOMPtr<nsISerialEventTarget> managerThread =
    843                         GetManagerThread();
    844                     if (!managerThread || aResult.IsReject()) {
    845                       // The parent process died or we got shutdown
    846                       return GenericNonExclusivePromise::CreateAndReject(
    847                           NS_ERROR_FAILURE, __func__);
    848                     }
    849                     nsresult rv = std::get<0>(aResult.ResolveValue());
    850                     if (NS_FAILED(rv)) {
    851                       return GenericNonExclusivePromise::CreateAndReject(
    852                           rv, __func__);
    853                     }
    854                     OpenRemoteMediaManagerChildForProcess(
    855                         std::get<1>(std::move(aResult.ResolveValue())),
    856                         aLocation);
    857                     return GenericNonExclusivePromise::CreateAndResolve(
    858                         true, __func__);
    859                   });
    860      });
    861 
    862  // Let's make sure this promise is also run on the managerThread to avoid
    863  // situations where it would be run on a threadpool thread.
    864  // During bug 1794988 this was happening when enabling Utility for audio on
    865  // Android when running the sequence of tests
    866  //   dom/media/test/test_access_control.html
    867  //   dom/media/test/test_arraybuffer.html
    868  //
    869  // We would have a launched utility process but the promises would not have
    870  // been cleared, so any subsequent tentative to perform audio decoding would
    871  // think the process is not yet ran and it would try to wait on the pending
    872  // promises.
    873  p = p->Then(
    874      managerThread, __func__,
    875      [aLocation](
    876          const GenericNonExclusivePromise::ResolveOrRejectValue& aResult) {
    877        StaticMutexAutoLock lock(sLaunchMutex);
    878        sLaunchPromises[aLocation] = nullptr;
    879        return GenericNonExclusivePromise::CreateAndResolveOrReject(aResult,
    880                                                                    __func__);
    881      });
    882  utilityLaunchPromise = p;
    883  return utilityLaunchPromise;
    884 }
    885 
    886 /* static */
    887 TrackSupportSet RemoteMediaManagerChild::GetTrackSupport(
    888    RemoteMediaIn aLocation) {
    889  TrackSupportSet s{TrackSupport::None};
    890  switch (aLocation) {
    891    case RemoteMediaIn::GpuProcess:
    892      s = TrackSupport::DecodeVideo;
    893      if (StaticPrefs::media_use_remote_encoder_video()) {
    894        s += TrackSupport::EncodeVideo;
    895      }
    896      break;
    897    case RemoteMediaIn::RddProcess:
    898      s = TrackSupport::DecodeVideo;
    899      if (StaticPrefs::media_use_remote_encoder_video()) {
    900        s += TrackSupport::EncodeVideo;
    901      }
    902 #ifndef ANDROID
    903      // Only use RDD for audio coding if we don't have the utility process. If
    904      // we have a CDM (which we can't determine here) on Android, then we want
    905      // to perform both the video and audio decoding in the RDD so that they
    906      // can share the CDM instance.
    907      if (!StaticPrefs::media_utility_process_enabled())
    908 #endif
    909      {
    910        s += TrackSupport::DecodeAudio;
    911        if (StaticPrefs::media_use_remote_encoder_audio()) {
    912          s += TrackSupport::EncodeAudio;
    913        }
    914      }
    915      break;
    916    case RemoteMediaIn::UtilityProcess_Generic:
    917    case RemoteMediaIn::UtilityProcess_AppleMedia:
    918    case RemoteMediaIn::UtilityProcess_WMF:
    919      if (StaticPrefs::media_utility_process_enabled()) {
    920        s = TrackSupport::DecodeAudio;
    921        if (StaticPrefs::media_use_remote_encoder_audio()) {
    922          s += TrackSupport::EncodeAudio;
    923        }
    924      }
    925      break;
    926    case RemoteMediaIn::UtilityProcess_MFMediaEngineCDM:
    927 #ifdef MOZ_WMF_MEDIA_ENGINE
    928      // When we enable the media engine, it would need both tracks to
    929      // synchronize the a/v playback.
    930      if (StaticPrefs::media_wmf_media_engine_enabled()) {
    931        s = TrackSupportSet{TrackSupport::DecodeAudio,
    932                            TrackSupport::DecodeVideo};
    933      }
    934 #endif
    935      break;
    936    default:
    937      MOZ_ASSERT_UNREACHABLE("Undefined location!");
    938      break;
    939  }
    940  return s;
    941 }
    942 
    943 PRemoteDecoderChild* RemoteMediaManagerChild::AllocPRemoteDecoderChild(
    944    const RemoteDecoderInfoIPDL& /* not used */,
    945    const CreateDecoderParams::OptionSet& aOptions,
    946    const Maybe<layers::TextureFactoryIdentifier>& aIdentifier,
    947    const Maybe<uint64_t>& aMediaEngineId, const Maybe<TrackingId>& aTrackingId,
    948    PRemoteCDMChild* aCDM) {
    949  // RemoteDecoderModule is responsible for creating RemoteDecoderChild
    950  // classes.
    951  MOZ_ASSERT(false,
    952             "RemoteMediaManagerChild cannot create "
    953             "RemoteDecoderChild classes");
    954  return nullptr;
    955 }
    956 
    957 bool RemoteMediaManagerChild::DeallocPRemoteDecoderChild(
    958    PRemoteDecoderChild* actor) {
    959  RemoteDecoderChild* child = static_cast<RemoteDecoderChild*>(actor);
    960  child->IPDLActorDestroyed();
    961  return true;
    962 }
    963 
    964 PMFMediaEngineChild* RemoteMediaManagerChild::AllocPMFMediaEngineChild() {
    965  MOZ_ASSERT_UNREACHABLE(
    966      "RemoteMediaManagerChild cannot create MFMediaEngineChild classes");
    967  return nullptr;
    968 }
    969 
    970 bool RemoteMediaManagerChild::DeallocPMFMediaEngineChild(
    971    PMFMediaEngineChild* actor) {
    972 #ifdef MOZ_WMF_MEDIA_ENGINE
    973  MFMediaEngineChild* child = static_cast<MFMediaEngineChild*>(actor);
    974  child->IPDLActorDestroyed();
    975 #endif
    976  return true;
    977 }
    978 
    979 PMFCDMChild* RemoteMediaManagerChild::AllocPMFCDMChild(const nsAString&) {
    980  MOZ_ASSERT_UNREACHABLE(
    981      "RemoteMediaManagerChild cannot create PMFContentDecryptionModuleChild "
    982      "classes");
    983  return nullptr;
    984 }
    985 
    986 bool RemoteMediaManagerChild::DeallocPMFCDMChild(PMFCDMChild* actor) {
    987 #ifdef MOZ_WMF_CDM
    988  static_cast<MFCDMChild*>(actor)->IPDLActorDestroyed();
    989 #endif
    990  return true;
    991 }
    992 
    993 RemoteMediaManagerChild::RemoteMediaManagerChild(RemoteMediaIn aLocation)
    994    : mLocation(aLocation) {
    995  MOZ_ASSERT(mLocation == RemoteMediaIn::GpuProcess ||
    996             mLocation == RemoteMediaIn::RddProcess ||
    997             mLocation == RemoteMediaIn::UtilityProcess_Generic ||
    998             mLocation == RemoteMediaIn::UtilityProcess_AppleMedia ||
    999             mLocation == RemoteMediaIn::UtilityProcess_WMF ||
   1000             mLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM);
   1001 }
   1002 
   1003 /* static */
   1004 void RemoteMediaManagerChild::OpenRemoteMediaManagerChildForProcess(
   1005    Endpoint<PRemoteMediaManagerChild>&& aEndpoint, RemoteMediaIn aLocation) {
   1006  nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
   1007  if (!managerThread) {
   1008    // We've been shutdown, bail.
   1009    return;
   1010  }
   1011  MOZ_ASSERT(managerThread->IsOnCurrentThread());
   1012 
   1013  // For GPU process, make sure we always dispatch everything in sRecreateTasks,
   1014  // even if we fail since this is as close to being recreated as we will ever
   1015  // be.
   1016  auto runRecreateTasksIfNeeded = MakeScopeExit([aLocation]() {
   1017    if (aLocation == RemoteMediaIn::GpuProcess) {
   1018      for (Runnable* task : *sRecreateTasks) {
   1019        task->Run();
   1020      }
   1021      sRecreateTasks->Clear();
   1022    }
   1023  });
   1024 
   1025  // Only create RemoteMediaManagerChild, bind new endpoint and init
   1026  // ipdl if:
   1027  // 1) haven't init'd sRemoteMediaManagerChildForProcesses[aLocation]
   1028  // or
   1029  // 2) if ActorDestroy was called meaning the other end of the ipc channel was
   1030  //    torn down
   1031  // But for GPU process, we always recreate a new manager child.
   1032  MOZ_ASSERT(aLocation != RemoteMediaIn::SENTINEL);
   1033  auto& remoteDecoderManagerChild =
   1034      sRemoteMediaManagerChildForProcesses[aLocation];
   1035  if (aLocation != RemoteMediaIn::GpuProcess && remoteDecoderManagerChild &&
   1036      remoteDecoderManagerChild->CanSend()) {
   1037    return;
   1038  }
   1039  remoteDecoderManagerChild = nullptr;
   1040  if (aEndpoint.IsValid()) {
   1041    RefPtr<RemoteMediaManagerChild> manager =
   1042        new RemoteMediaManagerChild(aLocation);
   1043    if (aEndpoint.Bind(manager)) {
   1044      remoteDecoderManagerChild = manager;
   1045    }
   1046  }
   1047 }
   1048 
   1049 bool RemoteMediaManagerChild::DeallocShmem(mozilla::ipc::Shmem& aShmem) {
   1050  nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
   1051  if (!managerThread) {
   1052    return false;
   1053  }
   1054  if (!managerThread->IsOnCurrentThread()) {
   1055    MOZ_ALWAYS_SUCCEEDS(managerThread->Dispatch(NS_NewRunnableFunction(
   1056        "RemoteMediaManagerChild::DeallocShmem",
   1057        [self = RefPtr{this}, shmem = aShmem]() mutable {
   1058          if (self->CanSend()) {
   1059            self->PRemoteMediaManagerChild::DeallocShmem(shmem);
   1060          }
   1061        })));
   1062    return true;
   1063  }
   1064  return PRemoteMediaManagerChild::DeallocShmem(aShmem);
   1065 }
   1066 
   1067 struct SurfaceDescriptorUserData {
   1068  SurfaceDescriptorUserData(RemoteMediaManagerChild* aAllocator,
   1069                            SurfaceDescriptor& aSD)
   1070      : mAllocator(aAllocator), mSD(aSD) {}
   1071  ~SurfaceDescriptorUserData() { DestroySurfaceDescriptor(mAllocator, &mSD); }
   1072 
   1073  RefPtr<RemoteMediaManagerChild> mAllocator;
   1074  SurfaceDescriptor mSD;
   1075 };
   1076 
   1077 void DeleteSurfaceDescriptorUserData(void* aClosure) {
   1078  SurfaceDescriptorUserData* sd =
   1079      reinterpret_cast<SurfaceDescriptorUserData*>(aClosure);
   1080  delete sd;
   1081 }
   1082 
   1083 already_AddRefed<SourceSurface> RemoteMediaManagerChild::Readback(
   1084    const SurfaceDescriptorGPUVideo& aSD) {
   1085  // We can't use NS_DispatchAndSpinEventLoopUntilComplete here since that will
   1086  // spin the event loop while it waits. This function can be called from JS and
   1087  // we don't want that to happen.
   1088  nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
   1089  if (!managerThread) {
   1090    return nullptr;
   1091  }
   1092 
   1093  SurfaceDescriptor sd;
   1094  RefPtr<Runnable> task =
   1095      NS_NewRunnableFunction("RemoteMediaManagerChild::Readback", [&]() {
   1096        if (CanSend()) {
   1097          SendReadback(aSD, &sd);
   1098        }
   1099      });
   1100  SyncRunnable::DispatchToThread(managerThread, task);
   1101 
   1102  if (!IsSurfaceDescriptorValid(sd)) {
   1103    return nullptr;
   1104  }
   1105 
   1106  RefPtr<DataSourceSurface> source = GetSurfaceForDescriptor(sd);
   1107  if (!source) {
   1108    DestroySurfaceDescriptor(this, &sd);
   1109    NS_WARNING("Failed to map SurfaceDescriptor in Readback");
   1110    return nullptr;
   1111  }
   1112 
   1113  static UserDataKey sSurfaceDescriptor;
   1114  source->AddUserData(&sSurfaceDescriptor,
   1115                      new SurfaceDescriptorUserData(this, sd),
   1116                      DeleteSurfaceDescriptorUserData);
   1117 
   1118  return source.forget();
   1119 }
   1120 
   1121 already_AddRefed<Image> RemoteMediaManagerChild::TransferToImage(
   1122    const SurfaceDescriptorGPUVideo& aSD, const IntSize& aSize,
   1123    const ColorDepth& aColorDepth, YUVColorSpace aYUVColorSpace,
   1124    ColorSpace2 aColorPrimaries, TransferFunction aTransferFunction,
   1125    ColorRange aColorRange) {
   1126  // The Image here creates a TextureData object that takes ownership
   1127  // of the SurfaceDescriptor, and is responsible for making sure that
   1128  // it gets deallocated.
   1129  SurfaceDescriptorGPUVideo sd(aSD);
   1130  sd.get_SurfaceDescriptorRemoteDecoder().source() =
   1131      Some(GetVideoBridgeSourceFromRemoteMediaIn(mLocation));
   1132  return MakeAndAddRef<GPUVideoImage>(this, sd, aSize, aColorDepth,
   1133                                      aYUVColorSpace, aColorPrimaries,
   1134                                      aTransferFunction, aColorRange);
   1135 }
   1136 
   1137 void RemoteMediaManagerChild::DeallocateSurfaceDescriptor(
   1138    const SurfaceDescriptorGPUVideo& aSD) {
   1139  nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
   1140  if (!managerThread) {
   1141    return;
   1142  }
   1143  MOZ_ALWAYS_SUCCEEDS(managerThread->Dispatch(NS_NewRunnableFunction(
   1144      "RemoteMediaManagerChild::DeallocateSurfaceDescriptor",
   1145      [ref = RefPtr{this}, sd = aSD]() {
   1146        if (ref->CanSend()) {
   1147          ref->SendDeallocateSurfaceDescriptorGPUVideo(sd);
   1148        }
   1149      })));
   1150 }
   1151 
   1152 void RemoteMediaManagerChild::OnSetCurrent(
   1153    const SurfaceDescriptorGPUVideo& aSD) {
   1154  nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
   1155  if (!managerThread) {
   1156    return;
   1157  }
   1158  MOZ_ALWAYS_SUCCEEDS(managerThread->Dispatch(
   1159      NS_NewRunnableFunction("RemoteMediaManagerChild::OnSetCurrent",
   1160                             [ref = RefPtr{this}, sd = aSD]() {
   1161                               if (ref->CanSend()) {
   1162                                 ref->SendOnSetCurrent(sd);
   1163                               }
   1164                             })));
   1165 }
   1166 
   1167 /* static */ void RemoteMediaManagerChild::HandleRejectionError(
   1168    const RemoteMediaManagerChild* aDyingManager, RemoteMediaIn aLocation,
   1169    const ipc::ResponseRejectReason& aReason,
   1170    std::function<void(const MediaResult&)>&& aCallback) {
   1171  // If the channel goes down and CanSend() returns false, the IPDL promise will
   1172  // be rejected with SendError rather than ActorDestroyed. Both means the same
   1173  // thing and we can consider that the parent has crashed. The child can no
   1174  // longer be used.
   1175 
   1176  if (aLocation == RemoteMediaIn::GpuProcess) {
   1177    // The GPU process will get automatically restarted by the parent process.
   1178    // Once it has been restarted the ContentChild will receive the message and
   1179    // will call GetManager()->InitForGPUProcess.
   1180    // We defer reporting an error until we've recreated the RemoteDecoder
   1181    // manager so that it'll be safe for MediaFormatReader to recreate decoders
   1182    RunWhenGPUProcessRecreated(
   1183        aDyingManager,
   1184        NS_NewRunnableFunction(
   1185            "RemoteMediaManagerChild::HandleRejectionError",
   1186            [callback = std::move(aCallback)]() {
   1187              MediaResult error(
   1188                  NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_RDD_OR_GPU_ERR, __func__);
   1189              callback(error);
   1190            }));
   1191    return;
   1192  }
   1193 
   1194  nsresult err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_UTILITY_ERR;
   1195  if (aLocation == RemoteMediaIn::RddProcess) {
   1196    err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_RDD_OR_GPU_ERR;
   1197  } else if (aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) {
   1198    err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_MF_CDM_ERR;
   1199  }
   1200  // The RDD/utility process is restarted on demand and asynchronously, we can
   1201  // immediately inform the caller that a new en/decoder is needed. The process
   1202  // will then be restarted during the new en/decoder creation by
   1203  aCallback(MediaResult(err, __func__));
   1204 }
   1205 
   1206 void RemoteMediaManagerChild::HandleFatalError(const char* aMsg) {
   1207  dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherChildID());
   1208 }
   1209 
   1210 void RemoteMediaManagerChild::SetSupported(
   1211    RemoteMediaIn aLocation, const media::MediaCodecsSupported& aSupported) {
   1212  switch (aLocation) {
   1213    case RemoteMediaIn::GpuProcess:
   1214    case RemoteMediaIn::RddProcess:
   1215    case RemoteMediaIn::UtilityProcess_AppleMedia:
   1216    case RemoteMediaIn::UtilityProcess_Generic:
   1217    case RemoteMediaIn::UtilityProcess_WMF:
   1218    case RemoteMediaIn::UtilityProcess_MFMediaEngineCDM: {
   1219      StaticMutexAutoLock lock(sProcessSupportedMutex);
   1220      sProcessSupported[aLocation] = Some(aSupported);
   1221      break;
   1222    }
   1223    default:
   1224      MOZ_CRASH("Not to be used for any other process");
   1225  }
   1226 }
   1227 
   1228 #undef LOG
   1229 
   1230 }  // namespace mozilla