Skip to content

Commit

Permalink
Bug 1478208 - Implement HTMLMediaElement.allowedToPlay. r=alwu,bz
Browse files Browse the repository at this point in the history
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:
whatwg/html#3617 (comment)

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
  • Loading branch information
Chris Pearce committed Jul 25, 2018
1 parent ea042b2 commit 2e3c4bd
Show file tree
Hide file tree
Showing 8 changed files with 38 additions and 5 deletions.
6 changes: 6 additions & 0 deletions dom/html/HTMLMediaElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2522,6 +2522,12 @@ HTMLMediaElement::ResumeLoad(PreloadAction aAction)
}
}

bool
HTMLMediaElement::AllowedToPlay() const
{
return AutoplayPolicy::IsAllowedToPlay(*this) == nsIAutoplay::ALLOWED;
}

void
HTMLMediaElement::UpdatePreloadAction()
{
Expand Down
6 changes: 6 additions & 0 deletions dom/html/HTMLMediaElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,12 @@ class HTMLMediaElement : public nsGenericHTMLElement,
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.
Expand Down
6 changes: 3 additions & 3 deletions dom/media/test/AutoplayTestUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}, "*");
}
);
}
Expand Down
3 changes: 2 additions & 1 deletion dom/media/test/test_autoplay_policy_activation.html
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
3 changes: 2 additions & 1 deletion dom/media/test/test_autoplay_policy_permission.html
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
10 changes: 10 additions & 0 deletions dom/webidl/HTMLMediaElement.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
8 changes: 8 additions & 0 deletions modules/libpref/init/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions testing/profiles/common/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);

0 comments on commit 2e3c4bd

Please sign in to comment.