diff --git a/docshell/base/WindowContext.cpp b/docshell/base/WindowContext.cpp index 89b2c7b2ccad..a9760ed85f64 100644 --- a/docshell/base/WindowContext.cpp +++ b/docshell/base/WindowContext.cpp @@ -200,6 +200,12 @@ bool WindowContext::CanSet(FieldIndex, return IsTop() && CheckOnlyOwningProcessCanSet(aSource); } +bool WindowContext::CanSet(FieldIndex, + const Maybe& aValue, + ContentParent* aSource) { + return IsTop(); +} + bool WindowContext::CanSet(FieldIndex, const uint32_t&, ContentParent* aSource) { return CheckOnlyOwningProcessCanSet(aSource); diff --git a/docshell/base/WindowContext.h b/docshell/base/WindowContext.h index 8db6ebbb0b42..4335cd31f7a8 100644 --- a/docshell/base/WindowContext.h +++ b/docshell/base/WindowContext.h @@ -64,6 +64,9 @@ class BrowsingContextGroup; FIELD(DocTreeHadAudibleMedia, bool) \ FIELD(AutoplayPermission, uint32_t) \ FIELD(ShortcutsPermission, uint32_t) \ + /* Store the Id of the browsing context where active media session \ + * exists on the top level window context */ \ + FIELD(ActiveMediaSessionContextId, Maybe) \ /* ALLOW_ACTION if it is allowed to open popups for the sub-tree \ * starting and including the current WindowContext */ \ FIELD(PopupPermission, uint32_t) \ @@ -213,6 +216,8 @@ class WindowContext : public nsISupports, public nsWrapperCache { ContentParent* aSource); bool CanSet(FieldIndex, const uint32_t& aValue, ContentParent* aSource); + bool CanSet(FieldIndex, + const Maybe& aValue, ContentParent* aSource); bool CanSet(FieldIndex, const uint32_t&, ContentParent* aSource); bool CanSet(FieldIndex, diff --git a/dom/media/mediacontrol/MediaStatusManager.cpp b/dom/media/mediacontrol/MediaStatusManager.cpp index 05f30e9de95a..84b1e0d93336 100644 --- a/dom/media/mediacontrol/MediaStatusManager.cpp +++ b/dom/media/mediacontrol/MediaStatusManager.cpp @@ -141,6 +141,7 @@ void MediaStatusManager::SetActiveMediaSessionContextId( return; } mActiveMediaSessionContextId = Some(aBrowsingContextId); + StoreMediaSessionContextIdOnWindowContext(); LOG("context %" PRIu64 " becomes active session context", *mActiveMediaSessionContextId); mMetadataChangedEvent.Notify(GetCurrentMediaMetadata()); @@ -153,10 +154,20 @@ void MediaStatusManager::ClearActiveMediaSessionContextIdIfNeeded() { } LOG("Clear active session context"); mActiveMediaSessionContextId.reset(); + StoreMediaSessionContextIdOnWindowContext(); mMetadataChangedEvent.Notify(GetCurrentMediaMetadata()); mSupportedActionsChangedEvent.Notify(GetSupportedActions()); } +void MediaStatusManager::StoreMediaSessionContextIdOnWindowContext() { + RefPtr bc = + CanonicalBrowsingContext::Get(mTopLevelBrowsingContextId); + if (bc && bc->GetTopWindowContext()) { + Unused << bc->GetTopWindowContext()->SetActiveMediaSessionContextId( + mActiveMediaSessionContextId); + } +} + bool MediaStatusManager::IsSessionOwningAudioFocus( uint64_t aBrowsingContextId) const { Maybe audioFocusContextId = diff --git a/dom/media/mediacontrol/MediaStatusManager.h b/dom/media/mediacontrol/MediaStatusManager.h index 4eaa31d28242..5fc766e77395 100644 --- a/dom/media/mediacontrol/MediaStatusManager.h +++ b/dom/media/mediacontrol/MediaStatusManager.h @@ -228,6 +228,8 @@ class MediaStatusManager : public IMediaInfoUpdater { // media event. CopyableTArray GetSupportedActions() const; + void StoreMediaSessionContextIdOnWindowContext(); + // When the amount of playing media changes, we would use this function to // update the guessed playback state. void SetGuessedPlayState(MediaSessionPlaybackState aState); diff --git a/dom/media/mediasession/MediaSession.cpp b/dom/media/mediasession/MediaSession.cpp index 7ccf7865c4e4..6b6907dbc58d 100644 --- a/dom/media/mediasession/MediaSession.cpp +++ b/dom/media/mediasession/MediaSession.cpp @@ -7,8 +7,16 @@ #include "mozilla/dom/BrowsingContext.h" #include "mozilla/dom/ContentMediaController.h" #include "mozilla/dom/MediaSession.h" +#include "mozilla/dom/MediaControlUtils.h" +#include "mozilla/dom/WindowContext.h" #include "mozilla/EnumeratedArrayCycleCollection.h" +// avoid redefined macro in unified build +#undef LOG +#define LOG(msg, ...) \ + MOZ_LOG(gMediaControlLog, LogLevel::Debug, \ + ("MediaSession=%p, " msg, this, ##__VA_ARGS__)) + namespace mozilla { namespace dom { @@ -166,6 +174,22 @@ bool MediaSession::IsSupportedAction(MediaSessionAction aAction) const { return mActionHandlers[aAction] != nullptr; } +bool MediaSession::IsActive() const { + RefPtr currentBC = GetParentObject()->GetBrowsingContext(); + MOZ_ASSERT(currentBC); + RefPtr wc = currentBC->GetTopWindowContext(); + if (!wc) { + return false; + } + Maybe activeSessionContextId = wc->GetActiveMediaSessionContextId(); + if (!activeSessionContextId) { + return false; + } + LOG("session context Id=%" PRIu64 ", active session context Id=%" PRIu64, + currentBC->Id(), *activeSessionContextId); + return *activeSessionContextId == currentBC->Id(); +} + void MediaSession::Shutdown() { NotifyMediaSessionStatus(SessionStatus::eDestroyed); } diff --git a/dom/media/mediasession/MediaSession.h b/dom/media/mediasession/MediaSession.h index 9e630b4f63db..82beee7e8ad8 100644 --- a/dom/media/mediasession/MediaSession.h +++ b/dom/media/mediasession/MediaSession.h @@ -69,6 +69,14 @@ class MediaSession final : public nsISupports, public nsWrapperCache { void Shutdown(); + // `MediaStatusManager` would determine which media session is an active media + // session and update it from the chrome process. This active session is not + // 100% equal to the active media session in the spec, which is a globally + // active media session *among all tabs*. The active session here is *among + // different windows but in same tab*, so each tab can have at most one + // active media session. + bool IsActive() const; + private: // Propagate media context status to the media session controller in the // chrome process when we create or destroy the media session.