tor-browser

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

AudioChannelAgent.cpp (9251B)


      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
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "AudioChannelAgent.h"
      6 
      7 #include "AudioChannelService.h"
      8 #include "mozilla/Preferences.h"
      9 #include "mozilla/dom/Document.h"
     10 #include "nsContentUtils.h"
     11 #include "nsPIDOMWindow.h"
     12 
     13 using namespace mozilla::dom;
     14 
     15 NS_IMPL_CYCLE_COLLECTION_CLASS(AudioChannelAgent)
     16 
     17 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioChannelAgent)
     18  tmp->Shutdown();
     19  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
     20  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
     21 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     22 
     23 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AudioChannelAgent)
     24  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
     25  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
     26 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     27 
     28 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AudioChannelAgent)
     29  NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgent)
     30  NS_INTERFACE_MAP_ENTRY(nsISupports)
     31 NS_INTERFACE_MAP_END
     32 
     33 NS_IMPL_CYCLE_COLLECTING_ADDREF(AudioChannelAgent)
     34 NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioChannelAgent)
     35 
     36 AudioChannelAgent::AudioChannelAgent()
     37    : mInnerWindowID(0), mIsRegToService(false) {
     38  // Init service in the begining, it can help us to know whether there is any
     39  // created media component via AudioChannelService::IsServiceStarted().
     40  RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
     41 }
     42 
     43 AudioChannelAgent::~AudioChannelAgent() { Shutdown(); }
     44 
     45 void AudioChannelAgent::Shutdown() {
     46  if (mIsRegToService) {
     47    NotifyStoppedPlaying();
     48  }
     49 }
     50 
     51 NS_IMETHODIMP
     52 AudioChannelAgent::Init(mozIDOMWindow* aWindow,
     53                        nsIAudioChannelAgentCallback* aCallback) {
     54  return InitInternal(nsPIDOMWindowInner::From(aWindow), aCallback,
     55                      /* useWeakRef = */ false);
     56 }
     57 
     58 NS_IMETHODIMP
     59 AudioChannelAgent::InitWithWeakCallback(
     60    mozIDOMWindow* aWindow, nsIAudioChannelAgentCallback* aCallback) {
     61  return InitInternal(nsPIDOMWindowInner::From(aWindow), aCallback,
     62                      /* useWeakRef = */ true);
     63 }
     64 
     65 nsresult AudioChannelAgent::FindCorrectWindow(nsPIDOMWindowInner* aWindow) {
     66  mWindow = aWindow->GetInProcessScriptableTop();
     67  if (NS_WARN_IF(!mWindow)) {
     68    return NS_OK;
     69  }
     70 
     71  // From here we do an hack for nested iframes.
     72  // The system app doesn't have access to the nested iframe objects so it
     73  // cannot control the volume of the agents running in nested apps. What we do
     74  // here is to assign those Agents to the top scriptable window of the parent
     75  // iframe (what is controlled by the system app).
     76  // For doing this we go recursively back into the chain of windows until we
     77  // find apps that are not the system one.
     78  nsCOMPtr<nsPIDOMWindowOuter> outerParent = mWindow->GetInProcessParent();
     79  if (!outerParent || outerParent == mWindow) {
     80    return NS_OK;
     81  }
     82 
     83  nsCOMPtr<nsPIDOMWindowInner> parent = outerParent->GetCurrentInnerWindow();
     84  if (!parent) {
     85    return NS_OK;
     86  }
     87 
     88  nsCOMPtr<Document> doc = parent->GetExtantDoc();
     89  if (!doc) {
     90    return NS_OK;
     91  }
     92 
     93  if (nsContentUtils::IsChromeDoc(doc)) {
     94    return NS_OK;
     95  }
     96 
     97  return FindCorrectWindow(parent);
     98 }
     99 
    100 nsresult AudioChannelAgent::InitInternal(
    101    nsPIDOMWindowInner* aWindow, nsIAudioChannelAgentCallback* aCallback,
    102    bool aUseWeakRef) {
    103  if (NS_WARN_IF(!aWindow)) {
    104    return NS_ERROR_FAILURE;
    105  }
    106 
    107  mInnerWindowID = aWindow->WindowID();
    108 
    109  nsresult rv = FindCorrectWindow(aWindow);
    110  if (NS_WARN_IF(NS_FAILED(rv))) {
    111    return rv;
    112  }
    113 
    114  if (aUseWeakRef) {
    115    mWeakCallback = do_GetWeakReference(aCallback);
    116  } else {
    117    mCallback = aCallback;
    118  }
    119 
    120  MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
    121          ("AudioChannelAgent, InitInternal, this = %p, "
    122           "owner = %p, hasCallback = %d\n",
    123           this, mWindow.get(), (!!mCallback || !!mWeakCallback)));
    124 
    125  return NS_OK;
    126 }
    127 
    128 void AudioChannelAgent::PullInitialUpdate() {
    129  RefPtr<AudioChannelService> service = AudioChannelService::Get();
    130  MOZ_ASSERT(service);
    131  MOZ_ASSERT(mIsRegToService);
    132 
    133  AudioPlaybackConfig config = service->GetMediaConfig(mWindow);
    134  MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
    135          ("AudioChannelAgent, PullInitialUpdate, this=%p, "
    136           "mute=%s, volume=%f, suspend=%s, audioCapturing=%s\n",
    137           this, config.mMuted ? "true" : "false", config.mVolume,
    138           SuspendTypeToStr(config.mSuspend),
    139           config.mCapturedAudio ? "true" : "false"));
    140  WindowVolumeChanged(config.mVolume, config.mMuted);
    141  WindowSuspendChanged(config.mSuspend);
    142  WindowAudioCaptureChanged(InnerWindowID(), config.mCapturedAudio);
    143 }
    144 
    145 NS_IMETHODIMP
    146 AudioChannelAgent::NotifyStartedPlaying(uint8_t aAudible) {
    147  RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
    148  if (service == nullptr || mIsRegToService) {
    149    return NS_ERROR_FAILURE;
    150  }
    151 
    152  MOZ_ASSERT(AudioChannelService::AudibleState::eNotAudible == 0 &&
    153             AudioChannelService::AudibleState::eMaybeAudible == 1 &&
    154             AudioChannelService::AudibleState::eAudible == 2);
    155  service->RegisterAudioChannelAgent(
    156      this, static_cast<AudioChannelService::AudibleState>(aAudible));
    157 
    158  MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
    159          ("AudioChannelAgent, NotifyStartedPlaying, this = %p, audible = %s\n",
    160           this,
    161           AudioChannelService::EnumValueToString(
    162               static_cast<AudioChannelService::AudibleState>(aAudible))));
    163 
    164  mIsRegToService = true;
    165  return NS_OK;
    166 }
    167 
    168 NS_IMETHODIMP
    169 AudioChannelAgent::NotifyStoppedPlaying() {
    170  if (!mIsRegToService) {
    171    return NS_ERROR_FAILURE;
    172  }
    173 
    174  MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
    175          ("AudioChannelAgent, NotifyStoppedPlaying, this = %p\n", this));
    176 
    177  RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
    178  if (service) {
    179    service->UnregisterAudioChannelAgent(this);
    180  }
    181 
    182  mIsRegToService = false;
    183  return NS_OK;
    184 }
    185 
    186 NS_IMETHODIMP
    187 AudioChannelAgent::NotifyStartedAudible(uint8_t aAudible, uint32_t aReason) {
    188  MOZ_LOG(
    189      AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
    190      ("AudioChannelAgent, NotifyStartedAudible, this = %p, "
    191       "audible = %s, reason = %s\n",
    192       this,
    193       AudioChannelService::EnumValueToString(
    194           static_cast<AudioChannelService::AudibleState>(aAudible)),
    195       AudioChannelService::EnumValueToString(
    196           static_cast<AudioChannelService::AudibleChangedReasons>(aReason))));
    197 
    198  RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
    199  if (NS_WARN_IF(!service)) {
    200    return NS_ERROR_FAILURE;
    201  }
    202 
    203  service->AudioAudibleChanged(
    204      this, static_cast<AudioChannelService::AudibleState>(aAudible),
    205      static_cast<AudioChannelService::AudibleChangedReasons>(aReason));
    206  return NS_OK;
    207 }
    208 
    209 already_AddRefed<nsIAudioChannelAgentCallback>
    210 AudioChannelAgent::GetCallback() {
    211  nsCOMPtr<nsIAudioChannelAgentCallback> callback = mCallback;
    212  if (!callback) {
    213    callback = do_QueryReferent(mWeakCallback);
    214  }
    215  return callback.forget();
    216 }
    217 
    218 void AudioChannelAgent::WindowVolumeChanged(float aVolume, bool aMuted) {
    219  nsCOMPtr<nsIAudioChannelAgentCallback> callback = GetCallback();
    220  if (!callback) {
    221    return;
    222  }
    223 
    224  MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
    225          ("AudioChannelAgent, WindowVolumeChanged, this = %p, mute = %s, "
    226           "volume = %f\n",
    227           this, aMuted ? "true" : "false", aVolume));
    228  callback->WindowVolumeChanged(aVolume, aMuted);
    229 }
    230 
    231 void AudioChannelAgent::WindowSuspendChanged(nsSuspendedTypes aSuspend) {
    232  nsCOMPtr<nsIAudioChannelAgentCallback> callback = GetCallback();
    233  if (!callback) {
    234    return;
    235  }
    236 
    237  MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
    238          ("AudioChannelAgent, WindowSuspendChanged, this = %p, "
    239           "suspended = %s\n",
    240           this, SuspendTypeToStr(aSuspend)));
    241  callback->WindowSuspendChanged(aSuspend);
    242 }
    243 
    244 AudioPlaybackConfig AudioChannelAgent::GetMediaConfig() const {
    245  RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
    246  AudioPlaybackConfig config(1.0, false, nsISuspendedTypes::NONE_SUSPENDED);
    247  if (service) {
    248    config = service->GetMediaConfig(mWindow);
    249  }
    250  return config;
    251 }
    252 
    253 uint64_t AudioChannelAgent::WindowID() const {
    254  return mWindow ? mWindow->WindowID() : 0;
    255 }
    256 
    257 uint64_t AudioChannelAgent::InnerWindowID() const { return mInnerWindowID; }
    258 
    259 void AudioChannelAgent::WindowAudioCaptureChanged(uint64_t aInnerWindowID,
    260                                                  bool aCapture) {
    261  if (aInnerWindowID != mInnerWindowID) {
    262    return;
    263  }
    264 
    265  nsCOMPtr<nsIAudioChannelAgentCallback> callback = GetCallback();
    266  if (!callback) {
    267    return;
    268  }
    269 
    270  MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
    271          ("AudioChannelAgent, WindowAudioCaptureChanged, this = %p, "
    272           "capture = %d\n",
    273           this, aCapture));
    274 
    275  callback->WindowAudioCaptureChanged(aCapture);
    276 }
    277 
    278 bool AudioChannelAgent::IsWindowAudioCapturingEnabled() const {
    279  return GetMediaConfig().mCapturedAudio;
    280 }
    281 
    282 bool AudioChannelAgent::IsPlayingStarted() const { return mIsRegToService; }