зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 4 changesets (bug 1665527
) for wpt leakchecks on setactionhandler.html . CLOSED TREE
Backed out changeset 216b96d6a2b3 (bug1665527
) Backed out changeset a683efbf01c1 (bug1665527
) Backed out changeset a18103008464 (bug1665527
) Backed out changeset b97b8759b686 (bug1665527
)
This commit is contained in:
Родитель
d8fa63f024
Коммит
691fd66153
|
@ -352,14 +352,7 @@ bool MediaController::ShouldActivateController() const {
|
||||||
|
|
||||||
bool MediaController::ShouldDeactivateController() const {
|
bool MediaController::ShouldDeactivateController() const {
|
||||||
MOZ_ASSERT(!mShutdown);
|
MOZ_ASSERT(!mShutdown);
|
||||||
// If we don't have an active media session and no controlled media exists,
|
return !IsAnyMediaBeingControlled() && mIsActive;
|
||||||
// then we don't need to keep controller active, because there is nothing to
|
|
||||||
// control. However, if we still have an active media session, then we should
|
|
||||||
// keep controller active in order to receive media keys even if we don't have
|
|
||||||
// any controlled media existing, because a website might start other media
|
|
||||||
// when media session receives media keys.
|
|
||||||
return !IsAnyMediaBeingControlled() && mIsActive &&
|
|
||||||
!mActiveMediaSessionContextId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaController::Activate() {
|
void MediaController::Activate() {
|
||||||
|
@ -506,11 +499,6 @@ void MediaController::HandleMetadataChanged(
|
||||||
// to use `getMetadata()` to get metadata, because it would throw an error if
|
// to use `getMetadata()` to get metadata, because it would throw an error if
|
||||||
// we fail to allocate artwork.
|
// we fail to allocate artwork.
|
||||||
DispatchAsyncEvent(u"metadatachange"_ns);
|
DispatchAsyncEvent(u"metadatachange"_ns);
|
||||||
// If metadata change is because of resetting active media session, then we
|
|
||||||
// should check if controller needs to be deactivated.
|
|
||||||
if (ShouldDeactivateController()) {
|
|
||||||
Deactivate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaController::DispatchAsyncEvent(const nsAString& aName) {
|
void MediaController::DispatchAsyncEvent(const nsAString& aName) {
|
||||||
|
|
|
@ -39,5 +39,4 @@ support-files =
|
||||||
[browser_nosrc_and_error_media.js]
|
[browser_nosrc_and_error_media.js]
|
||||||
[browser_seek_captured_audio.js]
|
[browser_seek_captured_audio.js]
|
||||||
[browser_stop_control_after_media_reaches_to_end.js]
|
[browser_stop_control_after_media_reaches_to_end.js]
|
||||||
[browser_remove_controllable_media_for_active_controller.js]
|
|
||||||
[browser_resume_latest_paused_media.js]
|
[browser_resume_latest_paused_media.js]
|
||||||
|
|
|
@ -1,115 +0,0 @@
|
||||||
/* eslint-disable no-undef */
|
|
||||||
const PAGE_URL =
|
|
||||||
"https://example.com/browser/dom/media/mediacontrol/tests/file_non_autoplay.html";
|
|
||||||
|
|
||||||
const testVideoId = "video";
|
|
||||||
|
|
||||||
add_task(async function setupTestingPref() {
|
|
||||||
await SpecialPowers.pushPrefEnv({
|
|
||||||
set: [["media.mediacontrol.testingevents.enabled", true]],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If an active controller has an active media session, then it can still be
|
|
||||||
* controlled via media key even if there is no controllable media presents.
|
|
||||||
* As active media session could still create other controllable media in its
|
|
||||||
* action handler, it should still receive media key. However, if a controller
|
|
||||||
* doesn't have an active media session, then it won't be controlled via media
|
|
||||||
* key when no controllable media presents.
|
|
||||||
*/
|
|
||||||
add_task(
|
|
||||||
async function testControllerWithActiveMediaSessionShouldStillBeActiveWhenNoControllableMediaPresents() {
|
|
||||||
info(`open media page`);
|
|
||||||
const tab = await createTabAndLoad(PAGE_URL);
|
|
||||||
|
|
||||||
info(`play media would activate controller and media session`);
|
|
||||||
await setupMediaSession(tab);
|
|
||||||
await playMedia(tab, testVideoId);
|
|
||||||
await checkOrWaitControllerBecomesActive(tab);
|
|
||||||
|
|
||||||
info(`remove playing media so we don't have any controllable media now`);
|
|
||||||
await removePlayingMedia(tab);
|
|
||||||
|
|
||||||
info(`despite that, controller should still be active`);
|
|
||||||
await checkOrWaitControllerBecomesActive(tab);
|
|
||||||
|
|
||||||
info(`active media session can still receive media key`);
|
|
||||||
await ensureActiveMediaSessionReceivedMediaKey(tab);
|
|
||||||
|
|
||||||
info(`remove tab`);
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
add_task(
|
|
||||||
async function testControllerWithoutActiveMediaSessionShouldBecomeInactiveWhenNoControllableMediaPresents() {
|
|
||||||
info(`open media page`);
|
|
||||||
const tab = await createTabAndLoad(PAGE_URL);
|
|
||||||
|
|
||||||
info(`play media would activate controller`);
|
|
||||||
await playMedia(tab, testVideoId);
|
|
||||||
await checkOrWaitControllerBecomesActive(tab);
|
|
||||||
|
|
||||||
info(`remove playing media so we don't have any controllable media now`);
|
|
||||||
await removePlayingMedia(tab);
|
|
||||||
|
|
||||||
info(`without having media session, controller should be deactivated`);
|
|
||||||
await checkOrWaitControllerBecomesInactive(tab);
|
|
||||||
|
|
||||||
info(`remove tab`);
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The following are helper functions.
|
|
||||||
*/
|
|
||||||
function setupMediaSession(tab) {
|
|
||||||
return SpecialPowers.spawn(tab.linkedBrowser, [], _ => {
|
|
||||||
// except `play/pause/stop`, set an action handler for arbitrary key in
|
|
||||||
// order to later verify if the session receives that media key by listening
|
|
||||||
// to session's `onpositionstatechange`.
|
|
||||||
content.navigator.mediaSession.setActionHandler("seekforward", _ => {
|
|
||||||
content.navigator.mediaSession.setPositionState({
|
|
||||||
duration: 60,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function ensureActiveMediaSessionReceivedMediaKey(tab) {
|
|
||||||
const controller = tab.linkedBrowser.browsingContext.mediaController;
|
|
||||||
const positionChangePromise = new Promise(
|
|
||||||
r => (controller.onpositionstatechange = r)
|
|
||||||
);
|
|
||||||
MediaControlService.generateMediaControlKey("seekforward");
|
|
||||||
await positionChangePromise;
|
|
||||||
ok(true, "active media session received media key");
|
|
||||||
}
|
|
||||||
|
|
||||||
function removePlayingMedia(tab) {
|
|
||||||
const controller = tab.linkedBrowser.browsingContext.mediaController;
|
|
||||||
return Promise.all([
|
|
||||||
new Promise(r => (controller.onplaybackstatechange = r)),
|
|
||||||
SpecialPowers.spawn(tab.linkedBrowser, [testVideoId], Id => {
|
|
||||||
content.document.getElementById(Id).remove();
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function checkOrWaitControllerBecomesActive(tab) {
|
|
||||||
const controller = tab.linkedBrowser.browsingContext.mediaController;
|
|
||||||
if (!controller.isActive) {
|
|
||||||
await new Promise(r => (controller.onactivated = r));
|
|
||||||
}
|
|
||||||
ok(controller.isActive, `controller is active`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function checkOrWaitControllerBecomesInactive(tab) {
|
|
||||||
const controller = tab.linkedBrowser.browsingContext.mediaController;
|
|
||||||
if (controller.isActive) {
|
|
||||||
await new Promise(r => (controller.ondeactivated = r));
|
|
||||||
}
|
|
||||||
ok(!controller.isActive, `controller is inacitve`);
|
|
||||||
}
|
|
|
@ -10,11 +10,9 @@ add_task(async function setupTestingPref() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This test is used to ensure that we would stop controlling media after it
|
* This test is used to ensure that we would stop controlling media after it
|
||||||
* reaches to the end when a controller doesn't have an active media session.
|
* reaches to the end.
|
||||||
* If a controller has an active media session, it would keep active despite
|
|
||||||
* media reaches to the end.
|
|
||||||
*/
|
*/
|
||||||
add_task(async function testControllerShouldStopAfterMediaReachesToTheEnd() {
|
add_task(async function testControlShouldStopAfterMediaReachesToTheEnd() {
|
||||||
info(`open media page and play media until the end`);
|
info(`open media page and play media until the end`);
|
||||||
const tab = await createTabAndLoad(PAGE_URL);
|
const tab = await createTabAndLoad(PAGE_URL);
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
|
@ -26,21 +24,6 @@ add_task(async function testControllerShouldStopAfterMediaReachesToTheEnd() {
|
||||||
await BrowserTestUtils.removeTab(tab);
|
await BrowserTestUtils.removeTab(tab);
|
||||||
});
|
});
|
||||||
|
|
||||||
add_task(async function testControllerWontStopAfterMediaReachesToTheEnd() {
|
|
||||||
info(`open media page and create media session`);
|
|
||||||
const tab = await createTabAndLoad(PAGE_URL);
|
|
||||||
await createMediaSession(tab);
|
|
||||||
|
|
||||||
info(`play media until the end`);
|
|
||||||
await playMediaUntilItReachesToTheEnd(tab);
|
|
||||||
|
|
||||||
info(`controller is still active because of having active media session`);
|
|
||||||
await checkControllerIsActive(tab);
|
|
||||||
|
|
||||||
info(`remove tab`);
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The following are helper functions.
|
* The following are helper functions.
|
||||||
*/
|
*/
|
||||||
|
@ -94,15 +77,3 @@ function playMediaUntilItReachesToTheEnd(tab) {
|
||||||
await new Promise(r => (video.onended = r));
|
await new Promise(r => (video.onended = r));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMediaSession(tab) {
|
|
||||||
return SpecialPowers.spawn(tab.linkedBrowser, [], _ => {
|
|
||||||
// simply create a media session, which would become the active media session later.
|
|
||||||
content.navigator.mediaSession;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkControllerIsActive(tab) {
|
|
||||||
const controller = tab.linkedBrowser.browsingContext.mediaController;
|
|
||||||
ok(controller.isActive, `controller is active`);
|
|
||||||
}
|
|
||||||
|
|
|
@ -27,40 +27,12 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaSession)
|
||||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaSession)
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaSession)
|
||||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaSession)
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaSession)
|
||||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDocumentActivity)
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
MediaSession::MediaSession(nsPIDOMWindowInner* aParent)
|
MediaSession::MediaSession(nsPIDOMWindowInner* aParent) : mParent(aParent) {
|
||||||
: mParent(aParent), mDoc(mParent->GetExtantDoc()) {
|
|
||||||
MOZ_ASSERT(mParent);
|
MOZ_ASSERT(mParent);
|
||||||
MOZ_ASSERT(mDoc);
|
NotifyMediaSessionStatus(SessionStatus::eCreated);
|
||||||
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; }
|
nsPIDOMWindowInner* MediaSession::GetParentObject() const { return mParent; }
|
||||||
|
@ -73,14 +45,12 @@ JSObject* MediaSession::WrapObject(JSContext* aCx,
|
||||||
MediaMetadata* MediaSession::GetMetadata() const { return mMediaMetadata; }
|
MediaMetadata* MediaSession::GetMetadata() const { return mMediaMetadata; }
|
||||||
|
|
||||||
void MediaSession::SetMetadata(MediaMetadata* aMetadata) {
|
void MediaSession::SetMetadata(MediaMetadata* aMetadata) {
|
||||||
MOZ_ASSERT(mSessionDocState == SessionDocStatus::eActive);
|
|
||||||
mMediaMetadata = aMetadata;
|
mMediaMetadata = aMetadata;
|
||||||
NotifyMetadataUpdated();
|
NotifyMetadataUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaSession::SetPlaybackState(
|
void MediaSession::SetPlaybackState(
|
||||||
const MediaSessionPlaybackState& aPlaybackState) {
|
const MediaSessionPlaybackState& aPlaybackState) {
|
||||||
MOZ_ASSERT(mSessionDocState == SessionDocStatus::eActive);
|
|
||||||
if (mDeclaredPlaybackState == aPlaybackState) {
|
if (mDeclaredPlaybackState == aPlaybackState) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -100,7 +70,6 @@ MediaSessionPlaybackState MediaSession::PlaybackState() const {
|
||||||
|
|
||||||
void MediaSession::SetActionHandler(MediaSessionAction aAction,
|
void MediaSession::SetActionHandler(MediaSessionAction aAction,
|
||||||
MediaSessionActionHandler* aHandler) {
|
MediaSessionActionHandler* aHandler) {
|
||||||
MOZ_ASSERT(mSessionDocState == SessionDocStatus::eActive);
|
|
||||||
MOZ_ASSERT(size_t(aAction) < ArrayLength(mActionHandlers));
|
MOZ_ASSERT(size_t(aAction) < ArrayLength(mActionHandlers));
|
||||||
// If the media session changes its supported action, then we would propagate
|
// 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
|
// this information to the chrome process in order to run the media session
|
||||||
|
@ -123,7 +92,6 @@ MediaSessionActionHandler* MediaSession::GetActionHandler(
|
||||||
|
|
||||||
void MediaSession::SetPositionState(const MediaPositionState& aState,
|
void MediaSession::SetPositionState(const MediaPositionState& aState,
|
||||||
ErrorResult& aRv) {
|
ErrorResult& aRv) {
|
||||||
MOZ_ASSERT(mSessionDocState == SessionDocStatus::eActive);
|
|
||||||
// https://w3c.github.io/mediasession/#dom-mediasession-setpositionstate
|
// https://w3c.github.io/mediasession/#dom-mediasession-setpositionstate
|
||||||
// If the state is an empty dictionary then clear the position state.
|
// If the state is an empty dictionary then clear the position state.
|
||||||
if (!aState.IsAnyMemberPresent()) {
|
if (!aState.IsAnyMemberPresent()) {
|
||||||
|
@ -222,7 +190,11 @@ bool MediaSession::IsActive() const {
|
||||||
return *activeSessionContextId == currentBC->Id();
|
return *activeSessionContextId == currentBC->Id();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaSession::NotifyMediaSessionDocStatus(SessionDocStatus aState) {
|
void MediaSession::Shutdown() {
|
||||||
|
NotifyMediaSessionStatus(SessionStatus::eDestroyed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaSession::NotifyMediaSessionStatus(SessionStatus aState) {
|
||||||
RefPtr<BrowsingContext> currentBC = GetParentObject()->GetBrowsingContext();
|
RefPtr<BrowsingContext> currentBC = GetParentObject()->GetBrowsingContext();
|
||||||
MOZ_ASSERT(currentBC, "Update session status after context destroyed!");
|
MOZ_ASSERT(currentBC, "Update session status after context destroyed!");
|
||||||
|
|
||||||
|
@ -230,7 +202,7 @@ void MediaSession::NotifyMediaSessionDocStatus(SessionDocStatus aState) {
|
||||||
if (!updater) {
|
if (!updater) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (aState == SessionDocStatus::eActive) {
|
if (aState == SessionStatus::eCreated) {
|
||||||
updater->NotifySessionCreated(currentBC->Id());
|
updater->NotifySessionCreated(currentBC->Id());
|
||||||
} else {
|
} else {
|
||||||
updater->NotifySessionDestroyed(currentBC->Id());
|
updater->NotifySessionDestroyed(currentBC->Id());
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include "mozilla/ErrorResult.h"
|
#include "mozilla/ErrorResult.h"
|
||||||
#include "mozilla/EnumeratedArray.h"
|
#include "mozilla/EnumeratedArray.h"
|
||||||
#include "nsCycleCollectionParticipant.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
#include "nsIDocumentActivity.h"
|
|
||||||
#include "nsWrapperCache.h"
|
#include "nsWrapperCache.h"
|
||||||
|
|
||||||
class nsPIDOMWindowInner;
|
class nsPIDOMWindowInner;
|
||||||
|
@ -36,12 +35,11 @@ struct PositionState {
|
||||||
double mLastReportedPlaybackPosition;
|
double mLastReportedPlaybackPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MediaSession final : public nsIDocumentActivity, public nsWrapperCache {
|
class MediaSession final : public nsISupports, public nsWrapperCache {
|
||||||
public:
|
public:
|
||||||
// Ref counting and cycle collection
|
// Ref counting and cycle collection
|
||||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaSession)
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaSession)
|
||||||
NS_DECL_NSIDOCUMENTACTIVITY
|
|
||||||
|
|
||||||
explicit MediaSession(nsPIDOMWindowInner* aParent);
|
explicit MediaSession(nsPIDOMWindowInner* aParent);
|
||||||
|
|
||||||
|
@ -80,18 +78,16 @@ class MediaSession final : public nsIDocumentActivity, public nsWrapperCache {
|
||||||
bool IsActive() const;
|
bool IsActive() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// When the document which media session belongs to is going to be destroyed,
|
// Propagate media context status to the media session controller in the
|
||||||
// or is in the bfcache, then the session would be inactive. Otherwise, it's
|
// chrome process when we create or destroy the media session.
|
||||||
// active all the time.
|
enum class SessionStatus : bool {
|
||||||
enum class SessionDocStatus : bool {
|
eDestroyed = false,
|
||||||
eInactive = false,
|
eCreated = true,
|
||||||
eActive = true,
|
|
||||||
};
|
};
|
||||||
void SetMediaSessionDocStatus(SessionDocStatus aState);
|
|
||||||
|
|
||||||
// These methods are used to propagate media session's status to the chrome
|
// These methods are used to propagate media session's status to the chrome
|
||||||
// process.
|
// process.
|
||||||
void NotifyMediaSessionDocStatus(SessionDocStatus aState);
|
void NotifyMediaSessionStatus(SessionStatus aState);
|
||||||
void NotifyMetadataUpdated();
|
void NotifyMetadataUpdated();
|
||||||
void NotifyEnableSupportedAction(MediaSessionAction aAction);
|
void NotifyEnableSupportedAction(MediaSessionAction aAction);
|
||||||
void NotifyDisableSupportedAction(MediaSessionAction aAction);
|
void NotifyDisableSupportedAction(MediaSessionAction aAction);
|
||||||
|
@ -118,8 +114,6 @@ class MediaSession final : public nsIDocumentActivity, public nsWrapperCache {
|
||||||
MediaSessionPlaybackState::None;
|
MediaSessionPlaybackState::None;
|
||||||
|
|
||||||
Maybe<PositionState> mPositionState;
|
Maybe<PositionState> mPositionState;
|
||||||
RefPtr<Document> mDoc;
|
|
||||||
SessionDocStatus mSessionDocState = SessionDocStatus::eInactive;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
Загрузка…
Ссылка в новой задаче