tor-browser

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

MediaStatusManager.cpp (19775B)


      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 "MediaStatusManager.h"
      6 
      7 #include "MediaControlService.h"
      8 #include "mozilla/StaticPrefs_media.h"
      9 #include "mozilla/dom/CanonicalBrowsingContext.h"
     10 #include "mozilla/dom/Element.h"
     11 #include "mozilla/dom/MediaControlUtils.h"
     12 #include "mozilla/dom/WindowGlobalParent.h"
     13 #include "nsContentUtils.h"
     14 #include "nsIChromeRegistry.h"
     15 #include "nsIObserverService.h"
     16 #include "nsIXULAppInfo.h"
     17 #include "nsNetUtil.h"
     18 
     19 #ifdef MOZ_PLACES
     20 #  include "nsIFaviconService.h"
     21 #endif  // MOZ_PLACES
     22 
     23 extern mozilla::LazyLogModule gMediaControlLog;
     24 
     25 // avoid redefined macro in unified build
     26 #undef LOG
     27 #define LOG(msg, ...)                        \
     28  MOZ_LOG(gMediaControlLog, LogLevel::Debug, \
     29          ("MediaStatusManager=%p, " msg, this, ##__VA_ARGS__))
     30 
     31 namespace mozilla::dom {
     32 
     33 static bool IsMetadataEmpty(const Maybe<MediaMetadataBase>& aMetadata) {
     34  // Media session's metadata is null.
     35  if (!aMetadata) {
     36    return true;
     37  }
     38 
     39  // All attirbutes in metadata are empty.
     40  // https://w3c.github.io/mediasession/#empty-metadata
     41  const MediaMetadataBase& metadata = *aMetadata;
     42  return metadata.mTitle.IsEmpty() && metadata.mArtist.IsEmpty() &&
     43         metadata.mAlbum.IsEmpty() && metadata.mArtwork.IsEmpty();
     44 }
     45 
     46 MediaStatusManager::MediaStatusManager(uint64_t aBrowsingContextId)
     47    : mTopLevelBrowsingContextId(aBrowsingContextId) {
     48  MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess(),
     49                        "MediaStatusManager only runs on Chrome process!");
     50 }
     51 
     52 void MediaStatusManager::NotifyMediaAudibleChanged(uint64_t aBrowsingContextId,
     53                                                   MediaAudibleState aState) {
     54  Maybe<uint64_t> oldAudioFocusOwnerId =
     55      mPlaybackStatusDelegate.GetAudioFocusOwnerContextId();
     56  mPlaybackStatusDelegate.UpdateMediaAudibleState(aBrowsingContextId, aState);
     57  Maybe<uint64_t> newAudioFocusOwnerId =
     58      mPlaybackStatusDelegate.GetAudioFocusOwnerContextId();
     59  if (oldAudioFocusOwnerId != newAudioFocusOwnerId) {
     60    HandleAudioFocusOwnerChanged(newAudioFocusOwnerId);
     61  }
     62 }
     63 
     64 void MediaStatusManager::NotifySessionCreated(uint64_t aBrowsingContextId) {
     65  const bool created = mMediaSessionInfoMap.WithEntryHandle(
     66      aBrowsingContextId, [&](auto&& entry) {
     67        if (entry) return false;
     68 
     69        LOG("Session %" PRIu64 " has been created", aBrowsingContextId);
     70        entry.Insert(MediaSessionInfo::EmptyInfo());
     71        return true;
     72      });
     73 
     74  if (created && IsSessionOwningAudioFocus(aBrowsingContextId)) {
     75    // This can't be done from within the WithEntryHandle functor, since it
     76    // accesses mMediaSessionInfoMap.
     77    SetActiveMediaSessionContextId(aBrowsingContextId);
     78  }
     79 }
     80 
     81 void MediaStatusManager::NotifySessionDestroyed(uint64_t aBrowsingContextId) {
     82  if (mMediaSessionInfoMap.Remove(aBrowsingContextId)) {
     83    LOG("Session %" PRIu64 " has been destroyed", aBrowsingContextId);
     84 
     85    if (mActiveMediaSessionContextId &&
     86        *mActiveMediaSessionContextId == aBrowsingContextId) {
     87      ClearActiveMediaSessionContextIdIfNeeded();
     88    }
     89  }
     90 }
     91 
     92 void MediaStatusManager::UpdateMetadata(
     93    uint64_t aBrowsingContextId, const Maybe<MediaMetadataBase>& aMetadata) {
     94  auto info = mMediaSessionInfoMap.Lookup(aBrowsingContextId);
     95  if (!info) {
     96    return;
     97  }
     98  if (IsMetadataEmpty(aMetadata)) {
     99    LOG("Reset metadata for session %" PRIu64, aBrowsingContextId);
    100    info->mMetadata.reset();
    101  } else {
    102    LOG("Update metadata for session %" PRIu64 " title=%s artist=%s album=%s",
    103        aBrowsingContextId, NS_ConvertUTF16toUTF8((*aMetadata).mTitle).get(),
    104        NS_ConvertUTF16toUTF8(aMetadata->mArtist).get(),
    105        NS_ConvertUTF16toUTF8(aMetadata->mAlbum).get());
    106    info->mMetadata = aMetadata;
    107  }
    108  // Only notify the event if the changed metadata belongs to the active media
    109  // session.
    110  if (mActiveMediaSessionContextId &&
    111      *mActiveMediaSessionContextId == aBrowsingContextId) {
    112    LOG("Notify metadata change for active session %" PRIu64,
    113        aBrowsingContextId);
    114    mMetadataChangedEvent.Notify(GetCurrentMediaMetadata());
    115  }
    116  if (StaticPrefs::media_mediacontrol_testingevents_enabled()) {
    117    if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
    118      obs->NotifyObservers(nullptr, "media-session-controller-metadata-changed",
    119                           nullptr);
    120    }
    121  }
    122 }
    123 
    124 void MediaStatusManager::HandleAudioFocusOwnerChanged(
    125    Maybe<uint64_t>& aBrowsingContextId) {
    126  // No one is holding the audio focus.
    127  if (!aBrowsingContextId) {
    128    LOG("No one is owning audio focus");
    129    return ClearActiveMediaSessionContextIdIfNeeded();
    130  }
    131 
    132  // This owner of audio focus doesn't have media session, so we should deactive
    133  // the active session because the active session must own the audio focus.
    134  if (!mMediaSessionInfoMap.Contains(*aBrowsingContextId)) {
    135    LOG("The owner of audio focus doesn't have media session");
    136    return ClearActiveMediaSessionContextIdIfNeeded();
    137  }
    138 
    139  // This owner has media session so it should become an active session context.
    140  SetActiveMediaSessionContextId(*aBrowsingContextId);
    141 }
    142 
    143 void MediaStatusManager::SetActiveMediaSessionContextId(
    144    uint64_t aBrowsingContextId) {
    145  if (mActiveMediaSessionContextId &&
    146      *mActiveMediaSessionContextId == aBrowsingContextId) {
    147    LOG("Active session context %" PRIu64 " keeps unchanged",
    148        *mActiveMediaSessionContextId);
    149    return;
    150  }
    151  mActiveMediaSessionContextId = Some(aBrowsingContextId);
    152  StoreMediaSessionContextIdOnWindowContext();
    153  LOG("context %" PRIu64 " becomes active session context",
    154      *mActiveMediaSessionContextId);
    155  mMetadataChangedEvent.Notify(GetCurrentMediaMetadata());
    156  mSupportedActionsChangedEvent.Notify(GetSupportedActions());
    157  mPositionStateChangedEvent.Notify(GetCurrentPositionState());
    158  if (StaticPrefs::media_mediacontrol_testingevents_enabled()) {
    159    if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
    160      obs->NotifyObservers(nullptr, "active-media-session-changed", nullptr);
    161    }
    162  }
    163 }
    164 
    165 void MediaStatusManager::ClearActiveMediaSessionContextIdIfNeeded() {
    166  if (!mActiveMediaSessionContextId) {
    167    return;
    168  }
    169  LOG("Clear active session context");
    170  mActiveMediaSessionContextId.reset();
    171  StoreMediaSessionContextIdOnWindowContext();
    172  mMetadataChangedEvent.Notify(GetCurrentMediaMetadata());
    173  mSupportedActionsChangedEvent.Notify(GetSupportedActions());
    174  mPositionStateChangedEvent.Notify(GetCurrentPositionState());
    175  if (StaticPrefs::media_mediacontrol_testingevents_enabled()) {
    176    if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
    177      obs->NotifyObservers(nullptr, "active-media-session-changed", nullptr);
    178    }
    179  }
    180 }
    181 
    182 void MediaStatusManager::StoreMediaSessionContextIdOnWindowContext() {
    183  RefPtr<CanonicalBrowsingContext> bc =
    184      CanonicalBrowsingContext::Get(mTopLevelBrowsingContextId);
    185  if (bc && bc->GetTopWindowContext()) {
    186    (void)bc->GetTopWindowContext()->SetActiveMediaSessionContextId(
    187        mActiveMediaSessionContextId);
    188  }
    189 }
    190 
    191 bool MediaStatusManager::IsSessionOwningAudioFocus(
    192    uint64_t aBrowsingContextId) const {
    193  Maybe<uint64_t> audioFocusContextId =
    194      mPlaybackStatusDelegate.GetAudioFocusOwnerContextId();
    195  return audioFocusContextId ? *audioFocusContextId == aBrowsingContextId
    196                             : false;
    197 }
    198 
    199 MediaMetadataBase MediaStatusManager::CreateDefaultMetadata() const {
    200  MediaMetadataBase metadata;
    201  metadata.mTitle = GetDefaultTitle();
    202  metadata.mUrl = GetUrl();
    203  metadata.mArtwork.AppendElement()->mSrc = GetDefaultFaviconURL();
    204 
    205  LOG("Default media metadata, title=%s, album src=%s",
    206      NS_ConvertUTF16toUTF8(metadata.mTitle).get(),
    207      NS_ConvertUTF16toUTF8(metadata.mArtwork[0].mSrc).get());
    208  return metadata;
    209 }
    210 
    211 nsString MediaStatusManager::GetDefaultTitle() const {
    212  RefPtr<MediaControlService> service = MediaControlService::GetService();
    213  nsString defaultTitle = service->GetFallbackTitle();
    214 
    215  RefPtr<CanonicalBrowsingContext> bc =
    216      CanonicalBrowsingContext::Get(mTopLevelBrowsingContextId);
    217  if (!bc) {
    218    return defaultTitle;
    219  }
    220 
    221  RefPtr<WindowGlobalParent> globalParent = bc->GetCurrentWindowGlobal();
    222  if (!globalParent) {
    223    return defaultTitle;
    224  }
    225 
    226  // The media metadata would be shown on the virtual controller interface. For
    227  // example, on Android, the interface would be shown on both notification bar
    228  // and lockscreen. Therefore, what information we provide via metadata is
    229  // quite important, because if we're in private browsing, we don't want to
    230  // expose details about what website the user is browsing on the lockscreen.
    231  // Therefore, using the default title when in the private browsing or the
    232  // document title is empty. Otherwise, use the document title.
    233  nsString documentTitle;
    234  if (!IsInPrivateBrowsing()) {
    235    globalParent->GetDocumentTitle(documentTitle);
    236  }
    237  return documentTitle.IsEmpty() ? defaultTitle : documentTitle;
    238 }
    239 
    240 nsCString MediaStatusManager::GetUrl() const {
    241  nsCString defaultUrl;
    242 
    243  RefPtr<CanonicalBrowsingContext> bc =
    244      CanonicalBrowsingContext::Get(mTopLevelBrowsingContextId);
    245  if (!bc) {
    246    return defaultUrl;
    247  }
    248 
    249  RefPtr<WindowGlobalParent> globalParent = bc->GetCurrentWindowGlobal();
    250  if (!globalParent) {
    251    return defaultUrl;
    252  }
    253 
    254  if (IsInPrivateBrowsing()) {
    255    return defaultUrl;
    256  }
    257 
    258  nsIURI* documentURI = globalParent->GetDocumentURI();
    259  if (!documentURI) {
    260    return defaultUrl;
    261  }
    262 
    263  return documentURI->GetSpecOrDefault();
    264 }
    265 
    266 nsString MediaStatusManager::GetDefaultFaviconURL() const {
    267 #ifdef MOZ_PLACES
    268  nsCOMPtr<nsIURI> faviconURI;
    269  nsresult rv = NS_NewURI(getter_AddRefs(faviconURI),
    270                          nsLiteralCString(FAVICON_DEFAULT_URL));
    271  NS_ENSURE_SUCCESS(rv, u""_ns);
    272 
    273  // Convert URI from `chrome://XXX` to `file://XXX` because we would like to
    274  // let OS related frameworks, such as SMTC and MPRIS, handle this URL in order
    275  // to show the icon on virtual controller interface.
    276  nsCOMPtr<nsIChromeRegistry> regService = services::GetChromeRegistry();
    277  if (!regService) {
    278    return u""_ns;
    279  }
    280  nsCOMPtr<nsIURI> processedURI;
    281  regService->ConvertChromeURL(faviconURI, getter_AddRefs(processedURI));
    282 
    283  nsAutoCString spec;
    284  if (NS_FAILED(processedURI->GetSpec(spec))) {
    285    return u""_ns;
    286  }
    287  return NS_ConvertUTF8toUTF16(spec);
    288 #else
    289  return u""_ns;
    290 #endif
    291 }
    292 
    293 void MediaStatusManager::SetDeclaredPlaybackState(
    294    uint64_t aBrowsingContextId, MediaSessionPlaybackState aState) {
    295  auto info = mMediaSessionInfoMap.Lookup(aBrowsingContextId);
    296  if (!info) {
    297    return;
    298  }
    299  LOG("SetDeclaredPlaybackState from %s to %s",
    300      ToMediaSessionPlaybackStateStr(info->mDeclaredPlaybackState),
    301      ToMediaSessionPlaybackStateStr(aState));
    302  info->mDeclaredPlaybackState = aState;
    303  UpdateActualPlaybackState();
    304 }
    305 
    306 MediaSessionPlaybackState MediaStatusManager::GetCurrentDeclaredPlaybackState()
    307    const {
    308  if (!mActiveMediaSessionContextId) {
    309    return MediaSessionPlaybackState::None;
    310  }
    311  return mMediaSessionInfoMap.Get(*mActiveMediaSessionContextId)
    312      .mDeclaredPlaybackState;
    313 }
    314 
    315 void MediaStatusManager::NotifyMediaPlaybackChanged(uint64_t aBrowsingContextId,
    316                                                    MediaPlaybackState aState) {
    317  LOG("UpdateMediaPlaybackState %s for context %" PRIu64,
    318      EnumValueToString(aState), aBrowsingContextId);
    319  const bool oldPlaying = mPlaybackStatusDelegate.IsPlaying();
    320  mPlaybackStatusDelegate.UpdateMediaPlaybackState(aBrowsingContextId, aState);
    321 
    322  // Playback state doesn't change, we don't need to update the guessed playback
    323  // state. This is used to prevent the state from changing from `none` to
    324  // `paused` when receiving `MediaPlaybackState::eStarted`.
    325  if (mPlaybackStatusDelegate.IsPlaying() == oldPlaying) {
    326    return;
    327  }
    328  if (mPlaybackStatusDelegate.IsPlaying()) {
    329    SetGuessedPlayState(MediaSessionPlaybackState::Playing);
    330  } else {
    331    SetGuessedPlayState(MediaSessionPlaybackState::Paused);
    332  }
    333 }
    334 
    335 void MediaStatusManager::SetGuessedPlayState(MediaSessionPlaybackState aState) {
    336  if (aState == mGuessedPlaybackState) {
    337    return;
    338  }
    339  LOG("SetGuessedPlayState : '%s'", ToMediaSessionPlaybackStateStr(aState));
    340  mGuessedPlaybackState = aState;
    341  UpdateActualPlaybackState();
    342 }
    343 
    344 void MediaStatusManager::UpdateActualPlaybackState() {
    345  // The way to compute the actual playback state is based on the spec.
    346  // https://w3c.github.io/mediasession/#actual-playback-state
    347  MediaSessionPlaybackState newState =
    348      GetCurrentDeclaredPlaybackState() == MediaSessionPlaybackState::Playing
    349          ? MediaSessionPlaybackState::Playing
    350          : mGuessedPlaybackState;
    351  if (mActualPlaybackState == newState) {
    352    return;
    353  }
    354  mActualPlaybackState = newState;
    355  LOG("UpdateActualPlaybackState : '%s'",
    356      ToMediaSessionPlaybackStateStr(mActualPlaybackState));
    357  mPlaybackStateChangedEvent.Notify(mActualPlaybackState);
    358 }
    359 
    360 void MediaStatusManager::EnableAction(uint64_t aBrowsingContextId,
    361                                      MediaSessionAction aAction) {
    362  auto info = mMediaSessionInfoMap.Lookup(aBrowsingContextId);
    363  if (!info) {
    364    return;
    365  }
    366  if (info->IsActionSupported(aAction)) {
    367    LOG("Action '%s' has already been enabled for context %" PRIu64,
    368        GetEnumString(aAction).get(), aBrowsingContextId);
    369    return;
    370  }
    371  LOG("Enable action %s for context %" PRIu64, GetEnumString(aAction).get(),
    372      aBrowsingContextId);
    373  info->EnableAction(aAction);
    374  NotifySupportedKeysChangedIfNeeded(aBrowsingContextId);
    375 }
    376 
    377 void MediaStatusManager::DisableAction(uint64_t aBrowsingContextId,
    378                                       MediaSessionAction aAction) {
    379  auto info = mMediaSessionInfoMap.Lookup(aBrowsingContextId);
    380  if (!info) {
    381    return;
    382  }
    383  if (!info->IsActionSupported(aAction)) {
    384    LOG("Action '%s' hasn't been enabled yet for context %" PRIu64,
    385        GetEnumString(aAction).get(), aBrowsingContextId);
    386    return;
    387  }
    388  LOG("Disable action %s for context %" PRIu64, GetEnumString(aAction).get(),
    389      aBrowsingContextId);
    390  info->DisableAction(aAction);
    391  NotifySupportedKeysChangedIfNeeded(aBrowsingContextId);
    392 }
    393 
    394 void MediaStatusManager::UpdatePositionState(
    395    uint64_t aBrowsingContextId, const Maybe<PositionState>& aState) {
    396  auto info = mMediaSessionInfoMap.Lookup(aBrowsingContextId);
    397  if (info) {
    398    LOG("Update position state for context %" PRIu64, aBrowsingContextId);
    399    info->mPositionState = aState;
    400  }
    401 
    402  // The position state comes from non-active media session which we don't care.
    403  if (!mActiveMediaSessionContextId ||
    404      *mActiveMediaSessionContextId != aBrowsingContextId) {
    405    return;
    406  }
    407  mPositionStateChangedEvent.Notify(aState);
    408 }
    409 
    410 void MediaStatusManager::UpdateGuessedPositionState(
    411    uint64_t aBrowsingContextId, const nsID& aMediaId,
    412    const Maybe<PositionState>& aGuessedState) {
    413  mPlaybackStatusDelegate.UpdateGuessedPositionState(aBrowsingContextId,
    414                                                     aMediaId, aGuessedState);
    415 
    416  // The position state comes from a non-active media session and
    417  // there is another one active (with some metadata).
    418  if (mActiveMediaSessionContextId &&
    419      *mActiveMediaSessionContextId != aBrowsingContextId) {
    420    return;
    421  }
    422 
    423  // media session is declared for the updated session, but there's no active
    424  // session - it will get emitted once the session becomes active
    425  if (mMediaSessionInfoMap.Contains(aBrowsingContextId) &&
    426      !mActiveMediaSessionContextId) {
    427    return;
    428  }
    429 
    430  mPositionStateChangedEvent.Notify(GetCurrentPositionState());
    431 }
    432 
    433 void MediaStatusManager::NotifySupportedKeysChangedIfNeeded(
    434    uint64_t aBrowsingContextId) {
    435  // Only the active media session's supported actions would be shown in virtual
    436  // control interface, so we only notify the event when supported actions
    437  // change happens on the active media session.
    438  if (!mActiveMediaSessionContextId ||
    439      *mActiveMediaSessionContextId != aBrowsingContextId) {
    440    return;
    441  }
    442  mSupportedActionsChangedEvent.Notify(GetSupportedActions());
    443 }
    444 
    445 CopyableTArray<MediaSessionAction> MediaStatusManager::GetSupportedActions()
    446    const {
    447  CopyableTArray<MediaSessionAction> supportedActions;
    448  if (!mActiveMediaSessionContextId) {
    449    return supportedActions;
    450  }
    451 
    452  MediaSessionInfo info =
    453      mMediaSessionInfoMap.Get(*mActiveMediaSessionContextId);
    454  for (MediaSessionAction action :
    455       MakeWebIDLEnumeratedRange<MediaSessionAction>()) {
    456    if (info.IsActionSupported(action)) {
    457      supportedActions.AppendElement(action);
    458    }
    459  }
    460  return supportedActions;
    461 }
    462 
    463 MediaMetadataBase MediaStatusManager::GetCurrentMediaMetadata() const {
    464  // If we don't have active media session, active media session doesn't have
    465  // media metadata, or we're in private browsing mode, then we should create a
    466  // default metadata which is using website's title and favicon as title and
    467  // artwork.
    468  if (mActiveMediaSessionContextId && !IsInPrivateBrowsing()) {
    469    MediaSessionInfo info =
    470        mMediaSessionInfoMap.Get(*mActiveMediaSessionContextId);
    471    if (!info.mMetadata) {
    472      return CreateDefaultMetadata();
    473    }
    474    MediaMetadataBase& metadata = *(info.mMetadata);
    475    FillMissingTitleAndArtworkIfNeeded(metadata);
    476    metadata.mUrl = GetUrl();
    477    return metadata;
    478  }
    479  return CreateDefaultMetadata();
    480 }
    481 
    482 Maybe<PositionState> MediaStatusManager::GetCurrentPositionState() const {
    483  if (mActiveMediaSessionContextId) {
    484    auto info = mMediaSessionInfoMap.Lookup(*mActiveMediaSessionContextId);
    485    if (info && info->mPositionState) {
    486      return info->mPositionState;
    487    }
    488  }
    489 
    490  return mPlaybackStatusDelegate.GuessedMediaPositionState(
    491      mActiveMediaSessionContextId);
    492 }
    493 
    494 void MediaStatusManager::FillMissingTitleAndArtworkIfNeeded(
    495    MediaMetadataBase& aMetadata) const {
    496  // If the metadata doesn't set its title and artwork properly, we would like
    497  // to use default title and favicon instead in order to prevent showing
    498  // nothing on the virtual control interface.
    499  if (aMetadata.mTitle.IsEmpty()) {
    500    aMetadata.mTitle = GetDefaultTitle();
    501  }
    502  if (aMetadata.mArtwork.IsEmpty()) {
    503    aMetadata.mArtwork.AppendElement()->mSrc = GetDefaultFaviconURL();
    504  }
    505 }
    506 
    507 bool MediaStatusManager::IsInPrivateBrowsing() const {
    508  RefPtr<CanonicalBrowsingContext> bc =
    509      CanonicalBrowsingContext::Get(mTopLevelBrowsingContextId);
    510  if (!bc) {
    511    return false;
    512  }
    513  RefPtr<Element> element = bc->GetEmbedderElement();
    514  if (!element) {
    515    return false;
    516  }
    517  return element->OwnerDoc()->IsInPrivateBrowsing();
    518 }
    519 
    520 MediaSessionPlaybackState MediaStatusManager::PlaybackState() const {
    521  return mActualPlaybackState;
    522 }
    523 
    524 bool MediaStatusManager::IsMediaAudible() const {
    525  return mPlaybackStatusDelegate.IsAudible();
    526 }
    527 
    528 bool MediaStatusManager::IsMediaPlaying() const {
    529  return mActualPlaybackState == MediaSessionPlaybackState::Playing;
    530 }
    531 
    532 bool MediaStatusManager::IsAnyMediaBeingControlled() const {
    533  return mPlaybackStatusDelegate.IsAnyMediaBeingControlled();
    534 }
    535 
    536 void MediaStatusManager::NotifyPageTitleChanged() {
    537  // If active media session has set non-empty metadata, then we would use that
    538  // instead of using default metadata.
    539  if (mActiveMediaSessionContextId &&
    540      mMediaSessionInfoMap.Lookup(*mActiveMediaSessionContextId)->mMetadata) {
    541    return;
    542  }
    543  // In private browsing mode, we won't show page title on default metadata so
    544  // we don't need to update that.
    545  if (IsInPrivateBrowsing()) {
    546    return;
    547  }
    548  LOG("page title changed, update default metadata");
    549  mMetadataChangedEvent.Notify(GetCurrentMediaMetadata());
    550 }
    551 
    552 }  // namespace mozilla::dom