I'm trying to determine whether the browser supports autoplay on load.
I'm using the following code, and it works fine on Android chrome, but for Desktop Chrome none of the lines in .catch or .then get executed. The promise seems to just return Pending promises ad infinitum.
Is this an actual Chrome bug or am I not understanding how Promises work here?
const promise = document.createElement('video').play();
if (promise instanceof Promise) {
promise.catch((error) => {
// Check if it is the right error
if (error.name === 'NotAllowedError') {
autoPlayAllowed = false;
} else {
throw error;
}
}).then(() => {
if (autoPlayAllowed) {
// Autoplay is allowed - continue with initialization
console.log('autoplay allowed')
} else {
// Autoplay is not allowed - wait for the user to trigger the play button manually
console.log('autoplay NOT allowed')
}
});
} else {
// Unknown if allowed
console.log('autoplay unknown')
}
Thanks!
MediaElement.play()
?The WHATWG spec has only recommended that MediaElement.play()
be Promisified since a Feb 2016 pull request following on from an issue submitted on Jan 2016. It is connected to the recent decision to prevent MediaElement
s from autoplaying (except under special conditions, such as these, for iOS Safari).
The W3C spec still (as of Nov 2017) does not appear to mention that MediaElement.play()
should return a Promise.
MediaElement.play()
returns a Promise as of version:
Firefox: 53 – [Mozilla docs]; [Mozilla Bugzilla]
'Chrome for Desktop', 'Chrome for Android', 'Android WebView': 50 – [Mozilla docs]; [Chrome platform status]
'Opera', 'Opera for Android': 37 – [Chrome platform status]
iOS Safari: iOS 10 – [WebKit's new video policies for iOS]
Desktop Safari: Jun 2017, so maybe v10.1.1 – [Autoplay policy changes for macOS]
The status of this change is unknown for Edge (feel free to comment).
The Chrome team have released a test page to check whether your own browser supports Promisified MediaElement.play()
.
If supported, the logging box will say:
Attempting to play automatically... The play() Promise fulfilled! Rock on!
Otherwise, it will only print the first line of those two.
MediaElement.play()
?Here are the best practices recommended by Jeff Posnick in a Google Developer blog post. Similar code is recommended in a WebKit blog post and by BitMovin, and they all derive from the original issue filing.
var playPromise = document.querySelector('video').play();
// In browsers that don’t yet support this functionality,
// playPromise won’t be defined.
if (playPromise !== undefined) {
playPromise.then(function() {
// Automatic playback started!
}).catch(function(error) {
// Automatic playback failed.
// Show a UI element to let the user manually start playback.
});
}
Basically: store the result of invoking MediaElement.play()
, and only act on it as a Promise chain if the result turns out to be non-undefined (eg. of type object
).
I am not sure if this is a bug or not, but you need to set an src
to your video before being able to fulfill or reject the play Promise.
Setting it to an empty string ""
will throw an "no supported source was found" error, but since in your original code you thrown unrecognized errors, the then
never fired.
So you could either rely on this "not found error" to tell that the autoplay works, or don't throw the error to go to the then.
let autoPlayAllowed = true;
let v = document.createElement('video');
v.src = ""; // we need this
const promise = v.play();
if (promise instanceof Promise) {
promise.catch(function(error) {
console.log(error.message);
// Check if it is the right error
if (error.name === 'NotAllowedError') {
autoPlayAllowed = false;
} else {
// Don't throw the error so that we get to the then
// or throw it but set the autoPlayAllowed to true in here
}
}).then(function() {
if (autoPlayAllowed) {
// Autoplay is allowed - continue with initialization
console.log('autoplay allowed')
} else {
// Autoplay is not allowed - wait for the user to trigger the play button manually
console.log('autoplay NOT allowed')
}
});
} else {
// Unknown if allowed
// Note: you could fallback to simple event listeners in this case
console.log('autoplay unknown')
}
Note that only WHATWG specs have included the promises in MediaElement.play()
, W3C didn't. So you may want to fallback to simple event listeners, at least for the time being.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With