Bug 1244592 - Fix non-autoplay click-to-play - r?cpearce
When media.autoplay.enabled==false, only videos may only be started through
direct user actions.
Unfortunately, for straight video files, the click-to-play handler defers
video.play() to a 0-timeout (to allow other scripts to consume the click if
they wish), which means the play() action arrives *outside* of the user-
interaction window; in which case it will be blocked.
The easiest solution is to send a play() then pause() immediately in the click
handler, so that the play() is not blocked; a side-effect is that the media
element remembers that user interaction has started, and will not block future
play()'s.
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -1085,28 +1085,49 @@
onFullscreenChange: function () {
if (this.isVideoInFullScreen()) {
Utils._hideControlsTimeout = setTimeout(this._hideControlsFn, this.HIDE_CONTROLS_TIMEOUT_MS);
}
this.setFullscreenButtonState();
},
+ clickToPlayInteractWithElement : function() {
+ // First time here, do play and pause now to simulate user
+ // interaction.
+ if (this.video.paused || this.video.ended) {
+ this.video.playbackRate = this.video.defaultPlaybackRate;
+ this.video.play();
+ this.video.pause();
+ } else {
+ this.video.pause();
+ this.video.playbackRate = this.video.defaultPlaybackRate;
+ this.video.play();
+ }
+ // Future calls will do nothing.
+ this.clickToPlayInteractWithElement = function() {};
+ },
clickToPlayClickHandler : function(e) {
if (e.button != 0)
return;
if (this.hasError() && !this.suppressError) {
// Errors that can be dismissed should be placed here as we discover them.
if (this.video.error.code != this.video.error.MEDIA_ERR_ABORTED)
return;
this.statusOverlay.hidden = true;
this.suppressError = true;
return;
}
+ // If not already started, send a quick play (and pause),
+ // so the media element thinks user interaction has happened
+ // when calling play() again in the timeout below (otherwise
+ // media.autoplay.enabled==false might block it).
+ this.clickToPlayInteractWithElement();
+
// Read defaultPrevented asynchronously, since Web content
// may want to consume the "click" event but will only
// receive it after us.
let self = this;
setTimeout(function clickToPlayCallback() {
if (!e.defaultPrevented)
self.togglePause();
}, 0);