Bug 1478208 - Implement HTMLMediaElement.allowedToPlay. r=alwu,bz

Various web authors have expressed desire to know in advance whether autoplay
will work.

They want this in order to avoid paying the price for downloading media that
won't play. Or they want to take other action such as showing a poster image
instead.

This is of particular interest to Firefox, as we're planning on showing a
prompt to ask the user whether they would like a site to play. If sites want to
determine whether they can autoplay but avoid the prompt showing, they won't be
able to just call play() in Firefox and see whether it works, as that would
likely show the prompt if the user doesn't already have a stored permission.

We've been working out a spec here:
https://github.com/whatwg/html/issues/3617#issuecomment-398613484

This implements what is the consensus to date there;
HTMLMediaElement.allowedToPlay, which returns true when a play() call would not
be blocked with NotAllowedError by autoplay blocking policies.

MozReview-Commit-ID: AkBu0G7uCJ0

--HG--
extra : rebase_source : 3f31db79aa1e570fdd9fc7062d0ddac7c96a8931
This commit is contained in:
Chris Pearce 2018-07-25 14:25:17 +12:00
Родитель ea042b2ab2
Коммит 2e3c4bd9af
8 изменённых файлов: 38 добавлений и 5 удалений

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

@ -2522,6 +2522,12 @@ HTMLMediaElement::ResumeLoad(PreloadAction aAction)
}
}
bool
HTMLMediaElement::AllowedToPlay() const
{
return AutoplayPolicy::IsAllowedToPlay(*this) == nsIAutoplay::ALLOWED;
}
void
HTMLMediaElement::UpdatePreloadAction()
{

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

@ -640,6 +640,12 @@ public:
mIsCasting = aShow;
}
// Returns whether a call to Play() would be rejected with NotAllowedError.
// This assumes "worst case" for unknowns. So if prompting for permission is
// enabled and no permission is stored, this behaves as if the user would
// opt to block.
bool AllowedToPlay() const;
already_AddRefed<MediaSource> GetMozMediaSourceObject() const;
// Returns a string describing the state of the media player internal
// data. Used for debugging purposes.

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

@ -5,13 +5,13 @@ function playAndPostResult(muted, parent_window) {
element.src = "short.mp4";
element.id = "video";
document.body.appendChild(element);
let allowedToPlay = element.allowedToPlay;
element.play().then(
() => {
parent_window.postMessage({played: true}, "*");
parent_window.postMessage({played: true, allowedToPlay}, "*");
},
() => {
parent_window.postMessage({played: false}, "*");
parent_window.postMessage({played: false, allowedToPlay}, "*");
}
);
}

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

@ -143,7 +143,8 @@
await once(child, "load");
child.postMessage(test_case, window.origin);
let result = await nextWindowMessage();
SimpleTest.is(result.data.played, test_case.should_play, test_case.name);
SimpleTest.is(result.data.allowedToPlay, test_case.should_play, "allowed - " + test_case.name);
SimpleTest.is(result.data.played, test_case.should_play, "played - " + test_case.name);
child.close();
}
SimpleTest.finish();

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

@ -34,7 +34,8 @@
child.postMessage("play-audible", testCase.origin);
// Wait for the window to tell us whether it could play video.
let result = await nextWindowMessage();
is(result.data.played, testCase.shouldPlay, testCase.message);
is(result.data.allowedToPlay, testCase.shouldPlay, "allowedToPlay - " + testCase.message);
is(result.data.played, testCase.shouldPlay, "played - " + testCase.message);
child.close();
}

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

@ -219,3 +219,13 @@ partial interface HTMLMediaElement {
[Pref="media.test.video-suspend"]
boolean hasSuspendTaint();
};
/*
* API that exposes whether a call to HTMLMediaElement.play() would be
* blocked by autoplay policies; whether the promise returned by play()
* would be rejected with NotAllowedError.
*/
partial interface HTMLMediaElement {
[Pref="media.allowed-to-play.enabled"]
readonly attribute boolean allowedToPlay;
};

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

@ -592,6 +592,14 @@ pref("media.autoplay.allow-extension-background-pages", true);
pref("media.autoplay.enabled.user-gestures-needed", false);
#endif
// HTMLMediaElement.allowedToPlay should be exposed to web content when
// block autoplay rides the trains to release. Until then, Nightly only.
#ifdef NIGHTLY_BUILD
pref("media.allowed-to-play.enabled", true);
#else
pref("media.allowed-to-play.enabled", false);
#endif
// The default number of decoded video frames that are enqueued in
// MediaDecoderReader's mVideoQueue.
pref("media.video-queue.default-size", 10);

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

@ -46,3 +46,4 @@ user_pref("media.autoplay.default", 0); // 0=Allowed, 1=Blocked, 2=Prompt
user_pref("media.autoplay.enabled.user-gestures-needed", true);
user_pref("media.autoplay.ask-permission", false);
user_pref("media.autoplay.block-webaudio", false);
user_pref("media.allowed-to-play.enabled", true);