video.js
video.js copied to clipboard
Video plays in native player with no image, only audio (iOS)
Description
Hello 👋
We've been having more issues recently with playing videos on Safari on iOS. The issue is that the video playing without an image, only with audio. It seems to occur when calling requestFullscreen
when the video starts playing when set up as in the repro link. Perhaps it somehow conflicts with the native fullscreen modus. The reason we're calling requestFullscreen
is to have the same behaviour across platforms. I then suspect users are closing the video and trying to restart it, causing our logs to get The object is in an invalid state.
errors. That error might be related to how we have set it up in React, rather than videojs itself, though.
The reduced test case shows this, but it did actually start to play once, so perhaps you will need to reload one or twice.
I am looking for any solution to not having the video without image. Right now I have hacked it to mitigate the problem by doing this:
player?.play()?.then(() => {
if (!shouldRequestFullscreenOnPlay) {
return;
}
// Calling requestFullscreen right after play seems to only crash on Safari on iOS
const promise = player?.requestFullscreen();
promise.catch((e) => {
const isWebkitFullscreenError = e.stack?.includes('webkitEnterFullScreen');
if (!isWebkitFullscreenError) {
// Log error...
}
});
});
It is basically counting on the requestFullscreen
to crash when it is called quickly after the play()
call, then checking if the call stack contains the webkitEnterFullScreen
, and if so, ignoring the error. This seems to work for other browsers with the video going fullscreen, and on iOS goes fullscreen natively anyway.
https://github.com/videojs/video.js/assets/5292940/02f61402-44bf-43ba-9af6-3d9bdda61c24
Reduced test case
https://codepen.io/petertflem/pen/KKEejPq
Steps to reproduce
- Load the link in Safari on iOS
- Click the custom, red play button.
- The video should play without image.
Errors
The error occurring when I suspect users try to restart the video. Might be connected to how we have set it up in React rather than video.js itself.
InvalidStateError The object is in an invalid state.
The callstack includes:
webkitEnterFullScreen
What version of Video.js are you using?
Recreated on 8.10.0 (We are using 7.20.3)
Video.js plugins used.
No response
What browser(s) including version(s) does this occur with?
Safari 17.2/17.3 and more
What OS(es) and version(s) does this occur with?
iOS
It works for me I wait for the playing
event instead of play
.
There doesn't seem to be a way to know the video element would be in this invalid state to enter fullscreen. webkitSupportsFullscreen
is true
and webkitDisplayingFullscreen
is false
at that point
Just another iOS Safari bug/peculiarity.
@mister-ben Thank you for your reply! 😄
It works for me as well when using the playing
event, but I still get the error InvalidStateError: The object is in an invalid state.
. This is probably better than the fix I made, but do you know if it is possible to avoid getting the error?
Thank you for your time!
If the element is playsinline
you wouldn't get the error, but you apparently still need to wait until playing
.
requestFullscreen()
returns the browser's promise, so you could also catch and handle or ignore the error there.
@mister-ben I think I might need to catch the error, though that would ignore all of those errors, so I was hoping to avoid it in case some actual InvalidStateError: The object is in an invalid state.
errors occurs. I tested with the playsinline
attribute for a bit, and in the beginning it seems to work. Then after a while, while pausing/playing and reloading the tab, it would start to only play inline. I don't know why it would change behaviour like that, but it seems like the playsinline
attribute somehow interferes with the request fullscreen, but only after using that tab for a while. Usually when opening a new tab, it would start working again, maybe except once. Then after a while, it would just play inline again, not expanding to fullscreen.
So catching the error might be the best option, even though we lose some of the error monitoring.