Bug 1665527 - part2 : notify media session status based on its document's activity state. r=chunmin

Because of D90771, we need media session to notifty its status correctly in order to deactivate the controller. Therefore, when its document becomes inactive (in bfcahce), we should treat media session as inactive and notify it to `MediaStatusManager` in order to clear the active media session if needed.

In addition, add some assertions to ensure we won't modify or set any attributes on media session when its document is inactive.

Differential Revision: https://phabricator.services.mozilla.com/D90926
This commit is contained in:
alwu 2020-09-22 21:46:13 +00:00
Родитель 2e937ee7bb
Коммит ad52a54195
2 изменённых файлов: 50 добавлений и 16 удалений

Просмотреть файл

@ -27,12 +27,40 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaSession)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaSession)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaSession)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIDocumentActivity)
NS_INTERFACE_MAP_END
MediaSession::MediaSession(nsPIDOMWindowInner* aParent) : mParent(aParent) {
MediaSession::MediaSession(nsPIDOMWindowInner* aParent)
: mParent(aParent), mDoc(mParent->GetExtantDoc()) {
MOZ_ASSERT(mParent);
NotifyMediaSessionStatus(SessionStatus::eCreated);
MOZ_ASSERT(mDoc);
mDoc->RegisterActivityObserver(this);
if (mDoc->IsCurrentActiveDocument()) {
SetMediaSessionDocStatus(SessionDocStatus::eActive);
}
}
void MediaSession::Shutdown() {
mDoc->UnregisterActivityObserver(this);
SetMediaSessionDocStatus(SessionDocStatus::eInactive);
}
void MediaSession::NotifyOwnerDocumentActivityChanged() {
const bool isDocActive = mDoc->IsCurrentActiveDocument();
LOG("Document activity changed, isActive=%d", isDocActive);
if (isDocActive) {
SetMediaSessionDocStatus(SessionDocStatus::eActive);
} else {
SetMediaSessionDocStatus(SessionDocStatus::eInactive);
}
}
void MediaSession::SetMediaSessionDocStatus(SessionDocStatus aState) {
if (mSessionDocState == aState) {
return;
}
mSessionDocState = aState;
NotifyMediaSessionDocStatus(mSessionDocState);
}
nsPIDOMWindowInner* MediaSession::GetParentObject() const { return mParent; }
@ -45,12 +73,14 @@ JSObject* MediaSession::WrapObject(JSContext* aCx,
MediaMetadata* MediaSession::GetMetadata() const { return mMediaMetadata; }
void MediaSession::SetMetadata(MediaMetadata* aMetadata) {
MOZ_ASSERT(mSessionDocState == SessionDocStatus::eActive);
mMediaMetadata = aMetadata;
NotifyMetadataUpdated();
}
void MediaSession::SetPlaybackState(
const MediaSessionPlaybackState& aPlaybackState) {
MOZ_ASSERT(mSessionDocState == SessionDocStatus::eActive);
if (mDeclaredPlaybackState == aPlaybackState) {
return;
}
@ -70,6 +100,7 @@ MediaSessionPlaybackState MediaSession::PlaybackState() const {
void MediaSession::SetActionHandler(MediaSessionAction aAction,
MediaSessionActionHandler* aHandler) {
MOZ_ASSERT(mSessionDocState == SessionDocStatus::eActive);
MOZ_ASSERT(size_t(aAction) < ArrayLength(mActionHandlers));
// If the media session changes its supported action, then we would propagate
// this information to the chrome process in order to run the media session
@ -92,6 +123,7 @@ MediaSessionActionHandler* MediaSession::GetActionHandler(
void MediaSession::SetPositionState(const MediaPositionState& aState,
ErrorResult& aRv) {
MOZ_ASSERT(mSessionDocState == SessionDocStatus::eActive);
// https://w3c.github.io/mediasession/#dom-mediasession-setpositionstate
// If the state is an empty dictionary then clear the position state.
if (!aState.IsAnyMemberPresent()) {
@ -190,11 +222,7 @@ bool MediaSession::IsActive() const {
return *activeSessionContextId == currentBC->Id();
}
void MediaSession::Shutdown() {
NotifyMediaSessionStatus(SessionStatus::eDestroyed);
}
void MediaSession::NotifyMediaSessionStatus(SessionStatus aState) {
void MediaSession::NotifyMediaSessionDocStatus(SessionDocStatus aState) {
RefPtr<BrowsingContext> currentBC = GetParentObject()->GetBrowsingContext();
MOZ_ASSERT(currentBC, "Update session status after context destroyed!");
@ -202,7 +230,7 @@ void MediaSession::NotifyMediaSessionStatus(SessionStatus aState) {
if (!updater) {
return;
}
if (aState == SessionStatus::eCreated) {
if (aState == SessionDocStatus::eActive) {
updater->NotifySessionCreated(currentBC->Id());
} else {
updater->NotifySessionDestroyed(currentBC->Id());

Просмотреть файл

@ -15,6 +15,7 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/EnumeratedArray.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIDocumentActivity.h"
#include "nsWrapperCache.h"
class nsPIDOMWindowInner;
@ -35,11 +36,12 @@ struct PositionState {
double mLastReportedPlaybackPosition;
};
class MediaSession final : public nsISupports, public nsWrapperCache {
class MediaSession final : public nsIDocumentActivity, public nsWrapperCache {
public:
// Ref counting and cycle collection
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaSession)
NS_DECL_NSIDOCUMENTACTIVITY
explicit MediaSession(nsPIDOMWindowInner* aParent);
@ -78,16 +80,18 @@ class MediaSession final : public nsISupports, public nsWrapperCache {
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.
enum class SessionStatus : bool {
eDestroyed = false,
eCreated = true,
// When the document which media session belongs to is going to be destroyed,
// or is in the bfcache, then the session would be inactive. Otherwise, it's
// active all the time.
enum class SessionDocStatus : bool {
eInactive = false,
eActive = true,
};
void SetMediaSessionDocStatus(SessionDocStatus aState);
// These methods are used to propagate media session's status to the chrome
// process.
void NotifyMediaSessionStatus(SessionStatus aState);
void NotifyMediaSessionDocStatus(SessionDocStatus aState);
void NotifyMetadataUpdated();
void NotifyEnableSupportedAction(MediaSessionAction aAction);
void NotifyDisableSupportedAction(MediaSessionAction aAction);
@ -114,6 +118,8 @@ class MediaSession final : public nsISupports, public nsWrapperCache {
MediaSessionPlaybackState::None;
Maybe<PositionState> mPositionState;
RefPtr<Document> mDoc;
SessionDocStatus mSessionDocState = SessionDocStatus::eInactive;
};
} // namespace dom