tor-browser

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

MediaStatusManager.h (12647B)


      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 #ifndef DOM_MEDIA_MEDIACONTROL_MEDIASTATUSMANAGER_H_
      6 #define DOM_MEDIA_MEDIACONTROL_MEDIASTATUSMANAGER_H_
      7 
      8 #include "MediaControlKeySource.h"
      9 #include "MediaEventSource.h"
     10 #include "MediaPlaybackStatus.h"
     11 #include "mozilla/Maybe.h"
     12 #include "mozilla/dom/MediaMetadata.h"
     13 #include "mozilla/dom/MediaSessionBinding.h"
     14 #include "nsISupportsImpl.h"
     15 #include "nsTHashMap.h"
     16 
     17 namespace mozilla::dom {
     18 
     19 class MediaSessionInfo {
     20 public:
     21  MediaSessionInfo() = default;
     22 
     23  explicit MediaSessionInfo(MediaMetadataBase& aMetadata) {
     24    mMetadata.emplace(aMetadata);
     25  }
     26 
     27  MediaSessionInfo(MediaMetadataBase& aMetadata,
     28                   MediaSessionPlaybackState& aState) {
     29    mMetadata.emplace(aMetadata);
     30    mDeclaredPlaybackState = aState;
     31  }
     32 
     33  static MediaSessionInfo EmptyInfo() { return MediaSessionInfo(); }
     34 
     35  static uint32_t GetActionBitMask(MediaSessionAction aAction) {
     36    return 1 << static_cast<uint8_t>(aAction);
     37  }
     38 
     39  void EnableAction(MediaSessionAction aAction) {
     40    mSupportedActions |= GetActionBitMask(aAction);
     41  }
     42 
     43  void DisableAction(MediaSessionAction aAction) {
     44    mSupportedActions &= ~GetActionBitMask(aAction);
     45  }
     46 
     47  bool IsActionSupported(MediaSessionAction aAction) const {
     48    return mSupportedActions & GetActionBitMask(aAction);
     49  }
     50 
     51  // These attributes are all propagated from the media session in the content
     52  // process.
     53  Maybe<MediaMetadataBase> mMetadata;
     54  MediaSessionPlaybackState mDeclaredPlaybackState =
     55      MediaSessionPlaybackState::None;
     56  Maybe<PositionState> mPositionState;
     57  // Use bitwise to store the supported actions.
     58  uint32_t mSupportedActions = 0;
     59 };
     60 
     61 /**
     62 * IMediaInfoUpdater is an interface which provides methods to update the media
     63 * related information that happens in the content process.
     64 */
     65 class IMediaInfoUpdater {
     66  NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
     67 
     68  // Use this method to update controlled media's playback state and the
     69  // browsing context where controlled media exists. When notifying the state
     70  // change, we MUST follow the following rules.
     71  // (1) `eStart` MUST be the first state and `eStop` MUST be the last state
     72  // (2) Do not notify same state again
     73  // (3) `ePaused` can only be notified after notifying `ePlayed`.
     74  virtual void NotifyMediaPlaybackChanged(uint64_t aBrowsingContextId,
     75                                          MediaPlaybackState aState) = 0;
     76 
     77  // Use this method to update the audible state of controlled media, and MUST
     78  // follow the following rules in which `audible` and `inaudible` should be a
     79  // pair. `inaudible` should always be notified after `audible`. When audible
     80  // media paused, `inaudible` should be notified
     81  // Eg. (O) `audible` -> `inaudible` -> `audible` -> `inaudible`
     82  //     (X) `inaudible` -> `audible`    [notify `inaudible` before `audible`]
     83  //     (X) `audible` -> `audible`      [notify `audible` twice]
     84  //     (X) `audible` -> (media pauses) [forgot to notify `inaudible`]
     85  virtual void NotifyMediaAudibleChanged(uint64_t aBrowsingContextId,
     86                                         MediaAudibleState aState) = 0;
     87 
     88  // Use this method to update media session's declared playback state for the
     89  // specific media session.
     90  virtual void SetDeclaredPlaybackState(uint64_t aBrowsingContextId,
     91                                        MediaSessionPlaybackState aState) = 0;
     92 
     93  // Use these methods to update controller's media session list. We'd use it
     94  // when media session is created/destroyed in the content process.
     95  virtual void NotifySessionCreated(uint64_t aBrowsingContextId) = 0;
     96  virtual void NotifySessionDestroyed(uint64_t aBrowsingContextId) = 0;
     97 
     98  // Use this method to update the metadata for the specific media session.
     99  virtual void UpdateMetadata(uint64_t aBrowsingContextId,
    100                              const Maybe<MediaMetadataBase>& aMetadata) = 0;
    101 
    102  // Use this method to update the picture in picture mode state of controlled
    103  // media, and it's safe to notify same state again.
    104  virtual void SetIsInPictureInPictureMode(uint64_t aBrowsingContextId,
    105                                           bool aIsInPictureInPictureMode) = 0;
    106 
    107  // Use these methods to update the supported media session action for the
    108  // specific media session. For a media session from a given browsing context,
    109  // do not re-enable the same action, or disable the action without enabling it
    110  // before.
    111  virtual void EnableAction(uint64_t aBrowsingContextId,
    112                            MediaSessionAction aAction) = 0;
    113  virtual void DisableAction(uint64_t aBrowsingContextId,
    114                             MediaSessionAction aAction) = 0;
    115 
    116  // Use this method when media enters or leaves the fullscreen.
    117  virtual void NotifyMediaFullScreenState(uint64_t aBrowsingContextId,
    118                                          bool aIsInFullScreen) = 0;
    119 
    120  // Use this method when media session update its position state.
    121  virtual void UpdatePositionState(uint64_t aBrowsingContextId,
    122                                   const Maybe<PositionState>& aState) = 0;
    123 
    124  // Use this method to update controlled media's position state and the
    125  // browsing context where controlled media exists.
    126  virtual void UpdateGuessedPositionState(
    127      uint64_t aBrowsingContextId, const nsID& aMediaId,
    128      const Maybe<PositionState>& aGuessedState) = 0;
    129 };
    130 
    131 /**
    132 * MediaStatusManager would decide the media related status which can represents
    133 * the whole tab. The status includes the playback status, tab's metadata and
    134 * the active media session ID if it exists.
    135 *
    136 * We would use `IMediaInfoUpdater` methods to update the media playback related
    137 * information and then use `MediaPlaybackStatus` to determine the final
    138 * playback state.
    139 *
    140 * The metadata would be the one from the active media session, or the default
    141 * one. This class would determine which media session is an active media
    142 * session [1] whithin a tab. It tracks all alive media sessions within a tab
    143 * and store their metadata which could be used to show on the virtual media
    144 * control interface. In addition, we can use it to get the current media
    145 * metadata even if there is no media session existing. However, the meaning of
    146 * active media session here is not equal to the definition from the spec [1].
    147 * We just choose the session which is the active one inside the tab, the global
    148 * active media session among different tabs would be the one inside the main
    149 * controller which is determined by MediaControlService.
    150 *
    151 * [1] https://w3c.github.io/mediasession/#active-media-session
    152 */
    153 class MediaStatusManager : public IMediaInfoUpdater {
    154 public:
    155  explicit MediaStatusManager(uint64_t aBrowsingContextId);
    156 
    157  // IMediaInfoUpdater's methods
    158  void NotifyMediaPlaybackChanged(uint64_t aBrowsingContextId,
    159                                  MediaPlaybackState aState) override;
    160  void NotifyMediaAudibleChanged(uint64_t aBrowsingContextId,
    161                                 MediaAudibleState aState) override;
    162  void SetDeclaredPlaybackState(uint64_t aSessionContextId,
    163                                MediaSessionPlaybackState aState) override;
    164  void NotifySessionCreated(uint64_t aSessionContextId) override;
    165  void NotifySessionDestroyed(uint64_t aSessionContextId) override;
    166  void UpdateMetadata(uint64_t aSessionContextId,
    167                      const Maybe<MediaMetadataBase>& aMetadata) override;
    168  void EnableAction(uint64_t aBrowsingContextId,
    169                    MediaSessionAction aAction) override;
    170  void DisableAction(uint64_t aBrowsingContextId,
    171                     MediaSessionAction aAction) override;
    172  void UpdatePositionState(uint64_t aBrowsingContextId,
    173                           const Maybe<PositionState>& aState) override;
    174  void UpdateGuessedPositionState(
    175      uint64_t aBrowsingContextId, const nsID& aMediaId,
    176      const Maybe<PositionState>& aGuessedState) override;
    177 
    178  // Return active media session's metadata if active media session exists and
    179  // it has already set its metadata. Otherwise, return default media metadata
    180  // which is based on website's title and favicon.
    181  MediaMetadataBase GetCurrentMediaMetadata() const;
    182 
    183  // Return the active media session's position state. If the active media
    184  // session doesn't exist or doesn't have any state, Nothing is returned.
    185  Maybe<PositionState> GetCurrentPositionState() const;
    186 
    187  bool IsMediaAudible() const;
    188  bool IsMediaPlaying() const;
    189  bool IsAnyMediaBeingControlled() const;
    190 
    191  // These events would be notified when the active media session's certain
    192  // property changes.
    193  MediaEventSource<MediaMetadataBase>& MetadataChangedEvent() {
    194    return mMetadataChangedEvent;
    195  }
    196 
    197  MediaEventSource<Maybe<PositionState>>& PositionChangedEvent() {
    198    return mPositionStateChangedEvent;
    199  }
    200 
    201  MediaEventSource<MediaSessionPlaybackState>& PlaybackChangedEvent() {
    202    return mPlaybackStateChangedEvent;
    203  }
    204 
    205  // Return the actual playback state.
    206  MediaSessionPlaybackState PlaybackState() const;
    207 
    208  // When page title changes, we might need to update it on the default
    209  // metadata as well.
    210  void NotifyPageTitleChanged();
    211 
    212 protected:
    213  ~MediaStatusManager() = default;
    214 
    215  // This event would be notified when the active media session changes its
    216  // supported actions.
    217  MediaEventSource<nsTArray<MediaSessionAction>>&
    218  SupportedActionsChangedEvent() {
    219    return mSupportedActionsChangedEvent;
    220  }
    221 
    222  uint64_t mTopLevelBrowsingContextId;
    223 
    224  // Within a tab, the Id of the browsing context which has already created a
    225  // media session and owns the audio focus within a tab.
    226  Maybe<uint64_t> mActiveMediaSessionContextId;
    227 
    228  void ClearActiveMediaSessionContextIdIfNeeded();
    229 
    230 private:
    231  nsString GetDefaultFaviconURL() const;
    232  nsString GetDefaultTitle() const;
    233  nsCString GetUrl() const;
    234  MediaMetadataBase CreateDefaultMetadata() const;
    235  bool IsInPrivateBrowsing() const;
    236  void FillMissingTitleAndArtworkIfNeeded(MediaMetadataBase& aMetadata) const;
    237 
    238  bool IsSessionOwningAudioFocus(uint64_t aBrowsingContextId) const;
    239  void SetActiveMediaSessionContextId(uint64_t aBrowsingContextId);
    240  void HandleAudioFocusOwnerChanged(Maybe<uint64_t>& aBrowsingContextId);
    241 
    242  void NotifySupportedKeysChangedIfNeeded(uint64_t aBrowsingContextId);
    243 
    244  // Return a copyable array filled with the supported media session actions.
    245  // Use copyable array so that we can use the result as a parameter for the
    246  // media event.
    247  CopyableTArray<MediaSessionAction> GetSupportedActions() const;
    248 
    249  void StoreMediaSessionContextIdOnWindowContext();
    250 
    251  // When the amount of playing media changes, we would use this function to
    252  // update the guessed playback state.
    253  void SetGuessedPlayState(MediaSessionPlaybackState aState);
    254 
    255  // Whenever the declared playback state or the guessed playback state changes,
    256  // we should recompute actual playback state to know if we need to update the
    257  // virtual control interface.
    258  void UpdateActualPlaybackState();
    259 
    260  // Return the active media session's declared playback state. If the active
    261  // media session doesn't exist, return  'None' instead.
    262  MediaSessionPlaybackState GetCurrentDeclaredPlaybackState() const;
    263 
    264  // This state can match to the `guessed playback state` in the spec [1], it
    265  // indicates if we have any media element playing within the tab which this
    266  // controller belongs to. But currently we only take media elements into
    267  // account, which is different from the way the spec recommends. In addition,
    268  // We don't support web audio and plugin and not consider audible state of
    269  // media.
    270  // [1] https://w3c.github.io/mediasession/#guessed-playback-state
    271  MediaSessionPlaybackState mGuessedPlaybackState =
    272      MediaSessionPlaybackState::None;
    273 
    274  // This playback state would be the final playback which can be used to know
    275  // if the controller is playing or not.
    276  // https://w3c.github.io/mediasession/#actual-playback-state
    277  MediaSessionPlaybackState mActualPlaybackState =
    278      MediaSessionPlaybackState::None;
    279 
    280  nsTHashMap<nsUint64HashKey, MediaSessionInfo> mMediaSessionInfoMap;
    281  MediaEventProducer<MediaMetadataBase> mMetadataChangedEvent;
    282  MediaEventProducer<nsTArray<MediaSessionAction>>
    283      mSupportedActionsChangedEvent;
    284  MediaEventProducer<Maybe<PositionState>> mPositionStateChangedEvent;
    285  MediaEventProducer<MediaSessionPlaybackState> mPlaybackStateChangedEvent;
    286  MediaPlaybackStatus mPlaybackStatusDelegate;
    287 };
    288 
    289 }  // namespace mozilla::dom
    290 
    291 #endif  // DOM_MEDIA_MEDIACONTROL_MEDIASTATUSMANAGER_H_