tor-browser

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

MediaControlKeyManager.cpp (7916B)


      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 "MediaControlKeyManager.h"
      6 
      7 #include "MediaControlService.h"
      8 #include "MediaControlUtils.h"
      9 #include "mozilla/AbstractThread.h"
     10 #include "mozilla/Logging.h"
     11 #include "mozilla/Preferences.h"
     12 #include "mozilla/Services.h"
     13 #include "mozilla/StaticPrefs_media.h"
     14 #include "mozilla/widget/MediaKeysEventSourceFactory.h"
     15 #include "nsContentUtils.h"
     16 #include "nsIObserverService.h"
     17 
     18 #undef LOG
     19 #define LOG(msg, ...)                        \
     20  MOZ_LOG(gMediaControlLog, LogLevel::Debug, \
     21          ("MediaControlKeyManager=%p, " msg, this, ##__VA_ARGS__))
     22 
     23 #undef LOG_INFO
     24 #define LOG_INFO(msg, ...)                  \
     25  MOZ_LOG(gMediaControlLog, LogLevel::Info, \
     26          ("MediaControlKeyManager=%p, " msg, this, ##__VA_ARGS__))
     27 
     28 #define MEDIA_CONTROL_PREF "media.hardwaremediakeys.enabled"
     29 
     30 namespace mozilla::dom {
     31 
     32 bool MediaControlKeyManager::IsOpened() const {
     33  return mEventSource && mEventSource->IsOpened();
     34 }
     35 
     36 bool MediaControlKeyManager::Open() {
     37  if (IsOpened()) {
     38    return true;
     39  }
     40  return StartMonitoringControlKeys();
     41 }
     42 
     43 void MediaControlKeyManager::Close() {
     44  // We don't call parent's `Close()` because we want to keep the listener
     45  // (MediaControlKeyHandler) all the time. It would be manually removed by
     46  // `MediaControlService` when shutdown.
     47  StopMonitoringControlKeys();
     48 }
     49 
     50 MediaControlKeyManager::MediaControlKeyManager()
     51    : mObserver(new Observer(this)) {
     52  nsContentUtils::RegisterShutdownObserver(mObserver);
     53  Preferences::AddStrongObserver(mObserver, MEDIA_CONTROL_PREF);
     54 }
     55 
     56 MediaControlKeyManager::~MediaControlKeyManager() { Shutdown(); }
     57 
     58 void MediaControlKeyManager::Shutdown() {
     59  StopMonitoringControlKeys();
     60  mEventSource = nullptr;
     61  if (mObserver) {
     62    nsContentUtils::UnregisterShutdownObserver(mObserver);
     63    Preferences::RemoveObserver(mObserver, MEDIA_CONTROL_PREF);
     64    mObserver = nullptr;
     65  }
     66 }
     67 
     68 bool MediaControlKeyManager::StartMonitoringControlKeys() {
     69  if (!StaticPrefs::media_hardwaremediakeys_enabled()) {
     70    return false;
     71  }
     72 
     73  if (!mEventSource) {
     74    mEventSource = widget::CreateMediaControlKeySource();
     75  }
     76  if (mEventSource && mEventSource->Open()) {
     77    LOG_INFO("StartMonitoringControlKeys");
     78    mEventSource->SetPlaybackState(mPlaybackState);
     79    mEventSource->SetMediaMetadata(mMetadata);
     80    mEventSource->SetSupportedMediaKeys(mSupportedKeys);
     81    mEventSource->AddListener(this);
     82    return true;
     83  }
     84  // Fail to open or create event source (eg. when cross-compiling with MinGW,
     85  // we cannot use the related WinAPI)
     86  return false;
     87 }
     88 
     89 void MediaControlKeyManager::StopMonitoringControlKeys() {
     90  if (!mEventSource || !mEventSource->IsOpened()) {
     91    return;
     92  }
     93 
     94  LOG_INFO("StopMonitoringControlKeys");
     95  mEventSource->Close();
     96  if (StaticPrefs::media_mediacontrol_testingevents_enabled()) {
     97    // Close the source would reset the displayed playback state and metadata.
     98    if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
     99      obs->NotifyObservers(nullptr, "media-displayed-playback-changed",
    100                           nullptr);
    101      obs->NotifyObservers(nullptr, "media-displayed-metadata-changed",
    102                           nullptr);
    103      obs->NotifyObservers(nullptr, "media-position-state-changed", nullptr);
    104    }
    105  }
    106 }
    107 
    108 void MediaControlKeyManager::OnActionPerformed(
    109    const MediaControlAction& aAction) {
    110  for (auto listener : mListeners) {
    111    listener->OnActionPerformed(aAction);
    112  }
    113 }
    114 
    115 void MediaControlKeyManager::SetPlaybackState(
    116    MediaSessionPlaybackState aState) {
    117  if (mEventSource && mEventSource->IsOpened()) {
    118    mEventSource->SetPlaybackState(aState);
    119  }
    120  mPlaybackState = aState;
    121  LOG_INFO("playbackState=%s", ToMediaSessionPlaybackStateStr(mPlaybackState));
    122  if (StaticPrefs::media_mediacontrol_testingevents_enabled()) {
    123    if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
    124      obs->NotifyObservers(nullptr, "media-displayed-playback-changed",
    125                           nullptr);
    126    }
    127  }
    128 }
    129 
    130 MediaSessionPlaybackState MediaControlKeyManager::GetPlaybackState() const {
    131  return (mEventSource && mEventSource->IsOpened())
    132             ? mEventSource->GetPlaybackState()
    133             : mPlaybackState;
    134 }
    135 
    136 void MediaControlKeyManager::SetMediaMetadata(
    137    const MediaMetadataBase& aMetadata) {
    138  if (mEventSource && mEventSource->IsOpened()) {
    139    mEventSource->SetMediaMetadata(aMetadata);
    140  }
    141  mMetadata = aMetadata;
    142  LOG_INFO("title=%s, artist=%s album=%s",
    143           NS_ConvertUTF16toUTF8(mMetadata.mTitle).get(),
    144           NS_ConvertUTF16toUTF8(mMetadata.mArtist).get(),
    145           NS_ConvertUTF16toUTF8(mMetadata.mAlbum).get());
    146  if (StaticPrefs::media_mediacontrol_testingevents_enabled()) {
    147    if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
    148      obs->NotifyObservers(nullptr, "media-displayed-metadata-changed",
    149                           nullptr);
    150    }
    151  }
    152 }
    153 
    154 void MediaControlKeyManager::SetSupportedMediaKeys(
    155    const MediaKeysArray& aSupportedKeys) {
    156  mSupportedKeys.Clear();
    157  for (const auto& key : aSupportedKeys) {
    158    LOG_INFO("Supported keys=%s", GetEnumString(key).get());
    159    mSupportedKeys.AppendElement(key);
    160  }
    161  if (mEventSource && mEventSource->IsOpened()) {
    162    mEventSource->SetSupportedMediaKeys(mSupportedKeys);
    163  }
    164 }
    165 
    166 void MediaControlKeyManager::SetEnableFullScreen(bool aIsEnabled) {
    167  LOG_INFO("Set fullscreen %s", aIsEnabled ? "enabled" : "disabled");
    168  if (mEventSource && mEventSource->IsOpened()) {
    169    mEventSource->SetEnableFullScreen(aIsEnabled);
    170  }
    171 }
    172 
    173 void MediaControlKeyManager::SetEnablePictureInPictureMode(bool aIsEnabled) {
    174  LOG_INFO("Set Picture-In-Picture mode %s",
    175           aIsEnabled ? "enabled" : "disabled");
    176  if (mEventSource && mEventSource->IsOpened()) {
    177    mEventSource->SetEnablePictureInPictureMode(aIsEnabled);
    178  }
    179 }
    180 
    181 void MediaControlKeyManager::SetPositionState(
    182    const Maybe<PositionState>& aState) {
    183  if (aState) {
    184    LOG_INFO("Set PositionState, duration=%f, playbackRate=%f, position=%f",
    185             aState->mDuration, aState->mPlaybackRate,
    186             aState->mLastReportedPlaybackPosition);
    187  } else {
    188    LOG_INFO("Set PositionState, Nothing");
    189  }
    190 
    191  if (mEventSource && mEventSource->IsOpened()) {
    192    mEventSource->SetPositionState(aState);
    193  }
    194 
    195  if (StaticPrefs::media_mediacontrol_testingevents_enabled()) {
    196    if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
    197      obs->NotifyObservers(nullptr, "media-position-state-changed", nullptr);
    198    }
    199  }
    200 }
    201 
    202 void MediaControlKeyManager::OnPreferenceChange() {
    203  const bool isPrefEnabled = StaticPrefs::media_hardwaremediakeys_enabled();
    204  // Only start monitoring control keys when the pref is on and having a main
    205  // controller that means already having media which need to be controlled.
    206  const bool shouldMonitorKeys =
    207      isPrefEnabled && MediaControlService::GetService()->GetMainController();
    208  LOG_INFO("Preference change : %s media control",
    209           isPrefEnabled ? "enable" : "disable");
    210  if (shouldMonitorKeys) {
    211    (void)StartMonitoringControlKeys();
    212  } else {
    213    StopMonitoringControlKeys();
    214  }
    215 }
    216 
    217 NS_IMPL_ISUPPORTS(MediaControlKeyManager::Observer, nsIObserver);
    218 
    219 MediaControlKeyManager::Observer::Observer(MediaControlKeyManager* aManager)
    220    : mManager(aManager) {}
    221 
    222 NS_IMETHODIMP
    223 MediaControlKeyManager::Observer::Observe(nsISupports* aSubject,
    224                                          const char* aTopic,
    225                                          const char16_t* aData) {
    226  if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
    227    mManager->Shutdown();
    228  } else if (!strcmp(aTopic, "nsPref:changed")) {
    229    mManager->OnPreferenceChange();
    230  }
    231  return NS_OK;
    232 }
    233 
    234 }  // namespace mozilla::dom