diff options
Diffstat (limited to 'dom/media/mediacontrol/MediaController.h')
-rw-r--r-- | dom/media/mediacontrol/MediaController.h | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/dom/media/mediacontrol/MediaController.h b/dom/media/mediacontrol/MediaController.h new file mode 100644 index 0000000000..0f0e624f6a --- /dev/null +++ b/dom/media/mediacontrol/MediaController.h @@ -0,0 +1,214 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DOM_MEDIA_MEDIACONTROL_MEDIACONTROLLER_H_ +#define DOM_MEDIA_MEDIACONTROL_MEDIACONTROLLER_H_ + +#include "MediaEventSource.h" +#include "MediaPlaybackStatus.h" +#include "MediaStatusManager.h" +#include "mozilla/DOMEventTargetHelper.h" +#include "mozilla/dom/MediaControllerBinding.h" +#include "mozilla/dom/MediaSession.h" +#include "mozilla/LinkedList.h" +#include "nsISupportsImpl.h" +#include "nsITimer.h" + +namespace mozilla::dom { + +class BrowsingContext; + +/** + * IMediaController is an interface which includes control related methods and + * methods used to know its playback state. + */ +class IMediaController { + public: + NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING + + // Focus the window currently playing media. + virtual void Focus() = 0; + virtual void Play() = 0; + virtual void Pause() = 0; + virtual void Stop() = 0; + virtual void PrevTrack() = 0; + virtual void NextTrack() = 0; + virtual void SeekBackward() = 0; + virtual void SeekForward() = 0; + virtual void SkipAd() = 0; + virtual void SeekTo(double aSeekTime, bool aFastSeek) = 0; + + // Return the ID of the top level browsing context within a tab. + virtual uint64_t Id() const = 0; + virtual bool IsAudible() const = 0; + virtual bool IsPlaying() const = 0; + virtual bool IsActive() const = 0; +}; + +/** + * MediaController is a class, which is used to control all media within a tab. + * It can only be used in Chrome process and the controlled media are usually + * in the content process (unless we disable e10s). + * + * Each tab would have only one media controller, they are 1-1 corresponding + * relationship, we use tab's top-level browsing context ID to initialize the + * controller and use that as its ID. + * + * The controller would be activated when its controlled media starts and + * becomes audible. After the controller is activated, then we can use its + * controlling methods, such as `Play()`, `Pause()` to control the media within + * the tab. + * + * If there is at least one controlled media playing in the tab, then we would + * say the controller is `playing`. If there is at least one controlled media is + * playing and audible, then we would say the controller is `audible`. + * + * Note that, if we don't enable audio competition, then we might have multiple + * tabs playing media at the same time, we can use the ID to query the specific + * controller from `MediaControlService`. + */ +class MediaController final : public DOMEventTargetHelper, + public IMediaController, + public LinkedListElement<RefPtr<MediaController>>, + public MediaStatusManager, + public nsITimerCallback, + public nsINamed { + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSITIMERCALLBACK + NS_DECL_NSINAMED + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(MediaController, + DOMEventTargetHelper) + explicit MediaController(uint64_t aBrowsingContextId); + + // WebIDL methods + nsISupports* GetParentObject() const; + JSObject* WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) override; + void GetSupportedKeys(nsTArray<MediaControlKey>& aRetVal) const; + void GetMetadata(MediaMetadataInit& aMetadata, ErrorResult& aRv); + IMPL_EVENT_HANDLER(activated); + IMPL_EVENT_HANDLER(deactivated); + IMPL_EVENT_HANDLER(metadatachange); + IMPL_EVENT_HANDLER(supportedkeyschange); + IMPL_EVENT_HANDLER(playbackstatechange); + IMPL_EVENT_HANDLER(positionstatechange); + + // IMediaController's methods + void Focus() override; + void Play() override; + void Pause() override; + void Stop() override; + void PrevTrack() override; + void NextTrack() override; + void SeekBackward() override; + void SeekForward() override; + void SkipAd() override; + void SeekTo(double aSeekTime, bool aFastSeek) override; + + uint64_t Id() const override; + bool IsAudible() const override; + bool IsPlaying() const override; + bool IsActive() const override; + + // IMediaInfoUpdater's methods + void NotifyMediaPlaybackChanged(uint64_t aBrowsingContextId, + MediaPlaybackState aState) override; + void NotifyMediaAudibleChanged(uint64_t aBrowsingContextId, + MediaAudibleState aState) override; + void SetIsInPictureInPictureMode(uint64_t aBrowsingContextId, + bool aIsInPictureInPictureMode) override; + void NotifyMediaFullScreenState(uint64_t aBrowsingContextId, + bool aIsInFullScreen) override; + + // Calling this method explicitly would mark this controller as deprecated, + // then calling any its method won't take any effect. + void Shutdown(); + + // This event would be notified media controller's supported media keys + // change. + MediaEventSource<nsTArray<MediaControlKey>>& SupportedKeysChangedEvent() { + return mSupportedKeysChangedEvent; + } + + MediaEventSource<bool>& FullScreenChangedEvent() { + return mFullScreenChangedEvent; + } + + MediaEventSource<bool>& PictureInPictureModeChangedEvent() { + return mPictureInPictureModeChangedEvent; + } + + CopyableTArray<MediaControlKey> GetSupportedMediaKeys() const; + + bool IsBeingUsedInPIPModeOrFullscreen() const; + + // These methods are used to select/unselect the media controller as a main + // controller. + void Select() const; + void Unselect() const; + + private: + ~MediaController(); + void HandleActualPlaybackStateChanged(); + void UpdateMediaControlActionToContentMediaIfNeeded( + const MediaControlAction& aAction); + void HandleSupportedMediaSessionActionsChanged( + const nsTArray<MediaSessionAction>& aSupportedAction); + + void HandlePositionStateChanged(const PositionState& aState); + void HandleMetadataChanged(const MediaMetadataBase& aMetadata); + + // This would register controller to the media control service that takes a + // responsibility to manage all active controllers. + void Activate(); + + // This would unregister controller from the media control service. + void Deactivate(); + + void UpdateActivatedStateIfNeeded(); + bool ShouldActivateController() const; + bool ShouldDeactivateController() const; + + void UpdateDeactivationTimerIfNeeded(); + + void DispatchAsyncEvent(const nsAString& aName); + void DispatchAsyncEvent(Event* aEvent); + + bool IsMainController() const; + void ForceToBecomeMainControllerIfNeeded(); + bool ShouldRequestForMainController() const; + + bool ShouldPropagateActionToAllContexts( + const MediaControlAction& aAction) const; + + bool mIsActive = false; + bool mShutdown = false; + bool mIsInPictureInPictureMode = false; + bool mIsInFullScreenMode = false; + + // We would monitor the change of media session actions and convert them to + // the media keys, then determine the supported media keys. + MediaEventListener mSupportedActionsChangedListener; + MediaEventProducer<nsTArray<MediaControlKey>> mSupportedKeysChangedEvent; + + MediaEventListener mPlaybackChangedListener; + MediaEventListener mPositionStateChangedListener; + MediaEventListener mMetadataChangedListener; + + MediaEventProducer<bool> mFullScreenChangedEvent; + MediaEventProducer<bool> mPictureInPictureModeChangedEvent; + // Use copyable array so that we can use the result as a parameter for the + // media event. + CopyableTArray<MediaControlKey> mSupportedKeys; + // Timer to deactivate the controller if the time of being paused exceeds the + // threshold of time. + nsCOMPtr<nsITimer> mDeactivationTimer; +}; + +} // namespace mozilla::dom + +#endif |