MediaController.h (7981B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef DOM_MEDIA_MEDIACONTROL_MEDIACONTROLLER_H_ 8 #define DOM_MEDIA_MEDIACONTROL_MEDIACONTROLLER_H_ 9 10 #include "MediaEventSource.h" 11 #include "MediaPlaybackStatus.h" 12 #include "MediaStatusManager.h" 13 #include "mozilla/DOMEventTargetHelper.h" 14 #include "mozilla/LinkedList.h" 15 #include "mozilla/dom/MediaControllerBinding.h" 16 #include "mozilla/dom/MediaSession.h" 17 #include "nsISupportsImpl.h" 18 #include "nsITimer.h" 19 20 namespace mozilla::dom { 21 22 class BrowsingContext; 23 24 /** 25 * IMediaController is an interface which includes control related methods and 26 * methods used to know its playback state. 27 */ 28 class IMediaController { 29 public: 30 NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING 31 32 // Focus the window currently playing media. 33 virtual void Focus() = 0; 34 virtual void Play() = 0; 35 virtual void Pause() = 0; 36 virtual void Stop() = 0; 37 virtual void PrevTrack() = 0; 38 virtual void NextTrack() = 0; 39 virtual void SeekBackward(double aSeekOffset) = 0; 40 virtual void SeekForward(double aSeekOffset) = 0; 41 virtual void SkipAd() = 0; 42 virtual void SeekTo(double aSeekTime, bool aFastSeek) = 0; 43 44 // Return the ID of the top level browsing context within a tab. 45 virtual uint64_t Id() const = 0; 46 virtual bool IsAudible() const = 0; 47 virtual bool IsPlaying() const = 0; 48 virtual bool IsActive() const = 0; 49 }; 50 51 /** 52 * MediaController is a class, which is used to control all media within a tab. 53 * It can only be used in Chrome process and the controlled media are usually 54 * in the content process (unless we disable e10s). 55 * 56 * Each tab would have only one media controller, they are 1-1 corresponding 57 * relationship, we use tab's top-level browsing context ID to initialize the 58 * controller and use that as its ID. 59 * 60 * The controller would be activated when its controlled media starts and 61 * becomes audible. After the controller is activated, then we can use its 62 * controlling methods, such as `Play()`, `Pause()` to control the media within 63 * the tab. 64 * 65 * If there is at least one controlled media playing in the tab, then we would 66 * say the controller is `playing`. If there is at least one controlled media is 67 * playing and audible, then we would say the controller is `audible`. 68 * 69 * Note that, if we don't enable audio competition, then we might have multiple 70 * tabs playing media at the same time, we can use the ID to query the specific 71 * controller from `MediaControlService`. 72 */ 73 class MediaController final : public DOMEventTargetHelper, 74 public IMediaController, 75 public LinkedListElement<RefPtr<MediaController>>, 76 public MediaStatusManager, 77 public nsITimerCallback, 78 public nsINamed { 79 public: 80 NS_DECL_ISUPPORTS_INHERITED 81 NS_DECL_NSITIMERCALLBACK 82 NS_DECL_NSINAMED 83 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(MediaController, 84 DOMEventTargetHelper) 85 explicit MediaController(uint64_t aBrowsingContextId); 86 87 // WebIDL methods 88 nsISupports* GetParentObject() const; 89 JSObject* WrapObject(JSContext* aCx, 90 JS::Handle<JSObject*> aGivenProto) override; 91 void GetSupportedKeys(nsTArray<MediaControlKey>& aRetVal) const; 92 void GetMetadata(MediaMetadataInit& aMetadata, ErrorResult& aRv); 93 IMPL_EVENT_HANDLER(activated); 94 IMPL_EVENT_HANDLER(deactivated); 95 IMPL_EVENT_HANDLER(metadatachange); 96 IMPL_EVENT_HANDLER(supportedkeyschange); 97 IMPL_EVENT_HANDLER(playbackstatechange); 98 IMPL_EVENT_HANDLER(positionstatechange); 99 100 // IMediaController's methods 101 void Focus() override; 102 void Play() override; 103 void Pause() override; 104 void Stop() override; 105 void PrevTrack() override; 106 void NextTrack() override; 107 void SeekBackward(double aSeekOffset) override; 108 void SeekForward(double aSeekOffset) override; 109 void SkipAd() override; 110 void SeekTo(double aSeekTime, bool aFastSeek) override; 111 112 uint64_t Id() const override; 113 bool IsAudible() const override; 114 bool IsPlaying() const override; 115 bool IsActive() const override; 116 117 // IMediaInfoUpdater's methods 118 void NotifyMediaPlaybackChanged(uint64_t aBrowsingContextId, 119 MediaPlaybackState aState) override; 120 void NotifyMediaAudibleChanged(uint64_t aBrowsingContextId, 121 MediaAudibleState aState) override; 122 void SetIsInPictureInPictureMode(uint64_t aBrowsingContextId, 123 bool aIsInPictureInPictureMode) override; 124 void NotifyMediaFullScreenState(uint64_t aBrowsingContextId, 125 bool aIsInFullScreen) override; 126 127 // Calling this method explicitly would mark this controller as deprecated, 128 // then calling any its method won't take any effect. 129 void Shutdown(); 130 131 // This event would be notified media controller's supported media keys 132 // change. 133 MediaEventSource<nsTArray<MediaControlKey>>& SupportedKeysChangedEvent() { 134 return mSupportedKeysChangedEvent; 135 } 136 137 MediaEventSource<bool>& FullScreenChangedEvent() { 138 return mFullScreenChangedEvent; 139 } 140 141 MediaEventSource<bool>& PictureInPictureModeChangedEvent() { 142 return mPictureInPictureModeChangedEvent; 143 } 144 145 CopyableTArray<MediaControlKey> GetSupportedMediaKeys() const; 146 147 bool IsBeingUsedInPIPModeOrFullscreen() const; 148 149 // These methods are used to select/unselect the media controller as a main 150 // controller. 151 void Select() const; 152 void Unselect() const; 153 154 private: 155 ~MediaController(); 156 void HandleActualPlaybackStateChanged(); 157 void UpdateMediaControlActionToContentMediaIfNeeded( 158 const MediaControlAction& aAction); 159 void HandleSupportedMediaSessionActionsChanged( 160 const nsTArray<MediaSessionAction>& aSupportedAction); 161 162 void HandlePositionStateChanged(const Maybe<PositionState>& aState); 163 void HandleMetadataChanged(const MediaMetadataBase& aMetadata); 164 165 // This would register controller to the media control service that takes a 166 // responsibility to manage all active controllers. 167 void Activate(); 168 169 // This would unregister controller from the media control service. 170 void Deactivate(); 171 172 void UpdateActivatedStateIfNeeded(); 173 bool ShouldActivateController() const; 174 bool ShouldDeactivateController() const; 175 176 void UpdateDeactivationTimerIfNeeded(); 177 178 void DispatchAsyncEvent(const nsAString& aName); 179 void DispatchAsyncEvent(already_AddRefed<Event> aEvent); 180 181 bool IsMainController() const; 182 void ForceToBecomeMainControllerIfNeeded(); 183 bool ShouldRequestForMainController() const; 184 185 bool ShouldPropagateActionToAllContexts( 186 const MediaControlAction& aAction) const; 187 188 bool mIsActive = false; 189 bool mShutdown = false; 190 bool mIsInPictureInPictureMode = false; 191 bool mIsInFullScreenMode = false; 192 193 // We would monitor the change of media session actions and convert them to 194 // the media keys, then determine the supported media keys. 195 MediaEventListener mSupportedActionsChangedListener; 196 MediaEventProducer<nsTArray<MediaControlKey>> mSupportedKeysChangedEvent; 197 198 MediaEventListener mPlaybackChangedListener; 199 MediaEventListener mPositionStateChangedListener; 200 MediaEventListener mMetadataChangedListener; 201 202 MediaEventProducer<bool> mFullScreenChangedEvent; 203 MediaEventProducer<bool> mPictureInPictureModeChangedEvent; 204 // Use copyable array so that we can use the result as a parameter for the 205 // media event. 206 CopyableTArray<MediaControlKey> mSupportedKeys; 207 // Timer to deactivate the controller if the time of being paused exceeds the 208 // threshold of time. 209 nsCOMPtr<nsITimer> mDeactivationTimer; 210 }; 211 212 } // namespace mozilla::dom 213 214 #endif