tor-browser

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

MediaPlaybackDelayPolicy.cpp (5203B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "MediaPlaybackDelayPolicy.h"
      6 
      7 #include "mozilla/StaticPrefs_media.h"
      8 #include "mozilla/dom/Document.h"
      9 #include "mozilla/dom/HTMLMediaElement.h"
     10 #include "nsPIDOMWindow.h"
     11 
     12 namespace mozilla::dom {
     13 
     14 using AudibleState = AudioChannelService::AudibleState;
     15 
     16 static AudibleState DetermineMediaAudibleState(const HTMLMediaElement* aElement,
     17                                               bool aIsAudible) {
     18  MOZ_ASSERT(aElement);
     19  if (!aElement->HasAudio()) {
     20    return AudibleState::eNotAudible;
     21  }
     22  // `eMaybeAudible` is used to distinguish if the media has audio track or not,
     23  // because we would only show the delayed media playback icon for media with
     24  // an audio track.
     25  return aIsAudible ? AudibleState::eAudible : AudibleState::eMaybeAudible;
     26 }
     27 
     28 ResumeDelayedPlaybackAgent::~ResumeDelayedPlaybackAgent() {
     29  if (mDelegate) {
     30    mDelegate->Clear();
     31    mDelegate = nullptr;
     32  }
     33 }
     34 
     35 bool ResumeDelayedPlaybackAgent::InitDelegate(const HTMLMediaElement* aElement,
     36                                              bool aIsAudible) {
     37  MOZ_ASSERT(!mDelegate, "Delegate has been initialized!");
     38  mDelegate = new ResumePlayDelegate();
     39  if (!mDelegate->Init(aElement, aIsAudible)) {
     40    mDelegate->Clear();
     41    mDelegate = nullptr;
     42    return false;
     43  }
     44  return true;
     45 }
     46 
     47 RefPtr<ResumeDelayedPlaybackAgent::ResumePromise>
     48 ResumeDelayedPlaybackAgent::GetResumePromise() {
     49  MOZ_ASSERT(mDelegate);
     50  return mDelegate->GetResumePromise();
     51 }
     52 
     53 void ResumeDelayedPlaybackAgent::UpdateAudibleState(
     54    const HTMLMediaElement* aElement, bool aIsAudible) {
     55  MOZ_ASSERT(aElement);
     56  MOZ_ASSERT(mDelegate);
     57  mDelegate->UpdateAudibleState(aElement, aIsAudible);
     58 }
     59 
     60 NS_IMPL_ISUPPORTS(ResumeDelayedPlaybackAgent::ResumePlayDelegate,
     61                  nsIAudioChannelAgentCallback)
     62 
     63 ResumeDelayedPlaybackAgent::ResumePlayDelegate::~ResumePlayDelegate() {
     64  MOZ_ASSERT(!mAudioChannelAgent);
     65 }
     66 
     67 bool ResumeDelayedPlaybackAgent::ResumePlayDelegate::Init(
     68    const HTMLMediaElement* aElement, bool aIsAudible) {
     69  MOZ_ASSERT(aElement);
     70  if (!aElement->OwnerDoc()->GetInnerWindow()) {
     71    return false;
     72  }
     73 
     74  MOZ_ASSERT(!mAudioChannelAgent);
     75  mAudioChannelAgent = new AudioChannelAgent();
     76  nsresult rv =
     77      mAudioChannelAgent->Init(aElement->OwnerDoc()->GetInnerWindow(), this);
     78  if (NS_WARN_IF(NS_FAILED(rv))) {
     79    Clear();
     80    return false;
     81  }
     82 
     83  // Start AudioChannelAgent in order to wait the suspended state change when we
     84  // are able to resume delayed playback.
     85  AudibleState audibleState = DetermineMediaAudibleState(aElement, aIsAudible);
     86  rv = mAudioChannelAgent->NotifyStartedPlaying(audibleState);
     87  if (NS_WARN_IF(NS_FAILED(rv))) {
     88    Clear();
     89    return false;
     90  }
     91 
     92  return true;
     93 }
     94 
     95 void ResumeDelayedPlaybackAgent::ResumePlayDelegate::Clear() {
     96  if (mAudioChannelAgent) {
     97    mAudioChannelAgent->NotifyStoppedPlaying();
     98    mAudioChannelAgent = nullptr;
     99  }
    100  mPromise.RejectIfExists(true, __func__);
    101 }
    102 
    103 RefPtr<ResumeDelayedPlaybackAgent::ResumePromise>
    104 ResumeDelayedPlaybackAgent::ResumePlayDelegate::GetResumePromise() {
    105  return mPromise.Ensure(__func__);
    106 }
    107 
    108 void ResumeDelayedPlaybackAgent::ResumePlayDelegate::UpdateAudibleState(
    109    const HTMLMediaElement* aElement, bool aIsAudible) {
    110  MOZ_ASSERT(aElement);
    111  // It's possible for the owner of `ResumeDelayedPlaybackAgent` to call
    112  // `UpdateAudibleState()` after we resolve the promise and clean resource.
    113  if (!mAudioChannelAgent) {
    114    return;
    115  }
    116  AudibleState audibleState = DetermineMediaAudibleState(aElement, aIsAudible);
    117  mAudioChannelAgent->NotifyStartedAudible(
    118      audibleState,
    119      AudioChannelService::AudibleChangedReasons::eDataAudibleChanged);
    120 }
    121 
    122 NS_IMETHODIMP
    123 ResumeDelayedPlaybackAgent::ResumePlayDelegate::WindowVolumeChanged(
    124    float aVolume, bool aMuted) {
    125  return NS_OK;
    126 }
    127 
    128 NS_IMETHODIMP
    129 ResumeDelayedPlaybackAgent::ResumePlayDelegate::WindowAudioCaptureChanged(
    130    bool aCapture) {
    131  return NS_OK;
    132 }
    133 
    134 NS_IMETHODIMP
    135 ResumeDelayedPlaybackAgent::ResumePlayDelegate::WindowSuspendChanged(
    136    SuspendTypes aSuspend) {
    137  if (aSuspend == nsISuspendedTypes::NONE_SUSPENDED) {
    138    mPromise.ResolveIfExists(true, __func__);
    139    Clear();
    140  }
    141  return NS_OK;
    142 }
    143 
    144 bool MediaPlaybackDelayPolicy::ShouldDelayPlayback(
    145    const HTMLMediaElement* aElement) {
    146  MOZ_ASSERT(aElement);
    147  if (!StaticPrefs::media_block_autoplay_until_in_foreground()) {
    148    return false;
    149  }
    150 
    151  const Document* doc = aElement->OwnerDoc();
    152  nsPIDOMWindowInner* inner = nsPIDOMWindowInner::From(doc->GetInnerWindow());
    153  nsPIDOMWindowOuter* outer = nsPIDOMWindowOuter::GetFromCurrentInner(inner);
    154  return outer && outer->ShouldDelayMediaFromStart();
    155 }
    156 
    157 RefPtr<ResumeDelayedPlaybackAgent>
    158 MediaPlaybackDelayPolicy::CreateResumeDelayedPlaybackAgent(
    159    const HTMLMediaElement* aElement, bool aIsAudible) {
    160  MOZ_ASSERT(aElement);
    161  RefPtr<ResumeDelayedPlaybackAgent> agent = new ResumeDelayedPlaybackAgent();
    162  return agent->InitDelegate(aElement, aIsAudible) ? agent : nullptr;
    163 }
    164 
    165 }  // namespace mozilla::dom