summaryrefslogtreecommitdiffstats
path: root/dom/media/mediacontrol/MediaControlService.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/mediacontrol/MediaControlService.h')
-rw-r--r--dom/media/mediacontrol/MediaControlService.h181
1 files changed, 181 insertions, 0 deletions
diff --git a/dom/media/mediacontrol/MediaControlService.h b/dom/media/mediacontrol/MediaControlService.h
new file mode 100644
index 0000000000..d0112ffe3c
--- /dev/null
+++ b/dom/media/mediacontrol/MediaControlService.h
@@ -0,0 +1,181 @@
+/* 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_MEDIACONTROLSERVICE_H_
+#define DOM_MEDIA_MEDIACONTROL_MEDIACONTROLSERVICE_H_
+
+#include "mozilla/AlreadyAddRefed.h"
+
+#include "AudioFocusManager.h"
+#include "MediaController.h"
+#include "MediaControlKeyManager.h"
+#include "mozilla/dom/MediaControllerBinding.h"
+#include "nsIObserver.h"
+#include "nsTArray.h"
+
+namespace mozilla::dom {
+
+/**
+ * MediaControlService is an interface to access controllers by providing
+ * controller Id. Everytime when controller becomes active, which means there is
+ * one or more media started in the corresponding browsing context, so now the
+ * controller is actually controlling something in the content process, so it
+ * would be added into the list of the MediaControlService. The controller would
+ * be removed from the list of the MediaControlService when it becomes inactive,
+ * which means no media is playing in the corresponding browsing context. Note
+ * that, a controller can't be added to or remove from the list twice. It should
+ * should have a responsibility to add and remove itself in the proper time.
+ */
+class MediaControlService final : public nsIObserver {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+
+ static RefPtr<MediaControlService> GetService();
+
+ // Currently these following static methods are only being used in testing.
+ static void GenerateMediaControlKey(const GlobalObject& global,
+ MediaControlKey aKey);
+ static void GetCurrentActiveMediaMetadata(const GlobalObject& aGlobal,
+ MediaMetadataInit& aMetadata);
+ static MediaSessionPlaybackState GetCurrentMediaSessionPlaybackState(
+ GlobalObject& aGlobal);
+
+ AudioFocusManager& GetAudioFocusManager() { return mAudioFocusManager; }
+ MediaControlKeySource* GetMediaControlKeySource() {
+ return mMediaControlKeyManager;
+ }
+
+ // Use these functions to register/unresgister controller to/from the active
+ // controller list in the service. Return true if the controller is registered
+ // or unregistered sucessfully.
+ bool RegisterActiveMediaController(MediaController* aController);
+ bool UnregisterActiveMediaController(MediaController* aController);
+ uint64_t GetActiveControllersNum() const;
+
+ // This method would be called when the controller changes its playback state.
+ void NotifyControllerPlaybackStateChanged(MediaController* aController);
+
+ // This method is used to help a media controller become a main controller, if
+ // it fits the requirement.
+ void RequestUpdateMainController(MediaController* aController);
+
+ // The main controller is the controller which can receive the media control
+ // key events and would show its metadata to virtual controller interface.
+ MediaController* GetMainController() const;
+
+ /**
+ * These following functions are used for testing only. We use them to
+ * generate fake media control key events, get the media metadata and playback
+ * state from the main controller.
+ */
+ void GenerateTestMediaControlKey(MediaControlKey aKey);
+ MediaMetadataBase GetMainControllerMediaMetadata() const;
+ MediaSessionPlaybackState GetMainControllerPlaybackState() const;
+
+ // Media title that should be used as a fallback. This commonly used
+ // when playing media in private browsing mode and we are trying to avoid
+ // exposing potentially sensitive titles.
+ nsString GetFallbackTitle() const;
+
+ // These functions are used to update the variable which would be used for
+ // telemetry probe.
+ void NotifyMediaControlHasEverBeenUsed();
+ void NotifyMediaControlHasEverBeenEnabled();
+
+ private:
+ MediaControlService();
+ ~MediaControlService();
+
+ /**
+ * When there are multiple media controllers existing, we would only choose
+ * one media controller as the main controller which can be controlled by
+ * media control keys event. The latest controller which is added into the
+ * service would become the main controller.
+ *
+ * However, as the main controller would be changed from time to time, so we
+ * create this wrapper to hold a real main controller if it exists. This class
+ * would also observe the playback state of controller in order to update the
+ * playback state of the event source.
+ *
+ * In addition, after finishing bug1592037, we would get the media metadata
+ * from the main controller, and update them to the event source in order to
+ * show those information on the virtual media controller interface on each
+ * platform.
+ */
+ class ControllerManager final {
+ public:
+ explicit ControllerManager(MediaControlService* aService);
+ ~ControllerManager() = default;
+
+ using MediaKeysArray = nsTArray<MediaControlKey>;
+ using LinkedListControllerPtr = LinkedListElement<RefPtr<MediaController>>*;
+ using ConstLinkedListControllerPtr =
+ const LinkedListElement<RefPtr<MediaController>>*;
+
+ bool AddController(MediaController* aController);
+ bool RemoveController(MediaController* aController);
+ void UpdateMainControllerIfNeeded(MediaController* aController);
+
+ void Shutdown();
+
+ MediaController* GetMainController() const;
+ bool Contains(MediaController* aController) const;
+ uint64_t GetControllersNum() const;
+
+ // These functions are used for monitoring main controller's status change.
+ void MainControllerPlaybackStateChanged(MediaSessionPlaybackState aState);
+ void MainControllerMetadataChanged(const MediaMetadataBase& aMetadata);
+
+ private:
+ // When applying `eInsertAsMainController`, we would always insert the
+ // element to the tail of the list. Eg. Insert C , [A, B] -> [A, B, C]
+ // When applying `eInsertAsNormalController`, we would insert the element
+ // prior to the element with a higher priority controller. Eg. Insert E and
+ // C and D have higher priority. [A, B, C, D] -> [A, B, E, C, D]
+ enum class InsertOptions {
+ eInsertAsMainController,
+ eInsertAsNormalController,
+ };
+
+ // Adjust the given controller's order by the insert option.
+ void ReorderGivenController(MediaController* aController,
+ InsertOptions aOption);
+
+ void UpdateMainControllerInternal(MediaController* aController);
+ void ConnectMainControllerEvents();
+ void DisconnectMainControllerEvents();
+
+ LinkedList<RefPtr<MediaController>> mControllers;
+ RefPtr<MediaController> mMainController;
+
+ // These member are use to listen main controller's play state changes and
+ // update the playback state to the event source.
+ RefPtr<MediaControlKeySource> mSource;
+ MediaEventListener mMetadataChangedListener;
+ MediaEventListener mSupportedKeysChangedListener;
+ MediaEventListener mFullScreenChangedListener;
+ MediaEventListener mPictureInPictureModeChangedListener;
+ MediaEventListener mPositionChangedListener;
+ };
+
+ void Init();
+ void Shutdown();
+
+ AudioFocusManager mAudioFocusManager;
+ RefPtr<MediaControlKeyManager> mMediaControlKeyManager;
+ RefPtr<MediaControlKeyListener> mMediaKeysHandler;
+ MediaEventProducer<uint64_t> mMediaControllerAmountChangedEvent;
+ UniquePtr<ControllerManager> mControllerManager;
+ nsString mFallbackTitle;
+
+ // Used for telemetry probe.
+ void UpdateTelemetryUsageProbe();
+ bool mHasEverUsedMediaControl = false;
+ bool mHasEverEnabledMediaControl = false;
+};
+
+} // namespace mozilla::dom
+
+#endif