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