rx-player
rx-player copied to clipboard
Infinity loading state on Safari Mobile when autoplay is false
For the "Pause TV" functionality, we set the autoplay property to false (ILoadVideoOptions
).
This causes RxPlayer to go into a perpetual loading/buffering state. The situation only applies to Safari Mobile.
(with autoplay: true it is ok.)
Device: iPhone 11 Pro with iOS 17.1 I tested on RxPlayer 3.33.0 and 3.29.0
Logs:
info: "API: Calling loadvideo" "https://tvvvideolive3.solocoo.tv/blueskytvvlive7hls/blueplay4/index.m3u8" "directfile"
log: "Locking contentLock to clean-up the current content."
info: "DRM: Clearing-up DRM session."
info: "DRM: Nothing to clear. Returning right away. No state =" true
log: "API: current media element state tick" "event" "init" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 0
info: "API: playerStateChange event" "LOADING"
log: "API: DRM session cleaned-up with success!"
log: "Unlocking contentLock. Next content can begin."
log: "Init: Creating ContentDecryptor"
log: "DRM: Starting ContentDecryptor logic."
info: "DRM: Searching for compatible MediaKeySystemAccess"
log: "DRM: Request keysystem access com.apple.fps.1_0,1 of 1"
info: "Init: Resume playback speed" 1
info: "DRM: Found compatible keysystem" "com.apple.fps.1_0" 1
info: "DRM: Calling createMediaKeys on the MediaKeySystemAccess"
info: "DRM: MediaKeys created with success"
info: "Setting URL to HTMLMediaElement" "https://tvvvideolive3.solocoo.tv/blueskytvvlive7hls/blueplay4/index.m3u8"
log: "DRM: Attaching current MediaKeys"
info: "DRM: Attaching MediaKeys to the media element"
info: "DRM: MediaKeys attached with success"
info: "DRM: Setting server certificate on the MediaKeys"
log: "API: current media element state tick" "event" "loadedmetadata" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\nloadedmetadata"
log: "Init: Calculating initial time"
log: "Init: Initial time calculated:" 0
info: "Init: Can begin to play content"
info: "Init: Set initial time" 0
info: "API: Seeking internally" 0
log: "API: current media element state tick" "event" "internal-seeking" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\nseeking"
log: "API: current media element state tick" "event" "seeked" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\nseeked"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
(...)
I checked on https://developers.canal-plus.com/rx-player/ (DirectFile
, Big Buck Bunny MP4
), If there is autoplay: false, the buffering indicator doesn't disapper, but the stream works fine when I press play.
It seems that Safari mobile here choose to not follow the preload: "auto"
hint unlike other browsers, so it doesn't preload anything until play
is called :/
A solution could be to add some exception (or detection?) when deciding whether to trigger the "LOADED"
state.
Interestingly, we already had a work-around just for Safari Mobile, but it seems that they changed something that made it not enough?
We could just make it "LOADED"
right away in Safari mobile for directfile contents, once the autoplay situation has been handled, though it will mean that it will be "LOADED"
but might buffer once you play, so that's not the same semantic than the usual "LOADED"
state.
We could also do a hack like calling play
+pause
(or maybe a seek?) but I'm wary of the consequences it could have here.
I can make a branch with the fix if you know how to test this.
Maybe we also broke our already-existing work-around because the comment description of it make the exact same observation you had.
So I'll also look at the history there.
I think I get it, before the work-around was only necessary for when the media element has the attribute "playsinline"
.
Though here, I guess you don't have "playsinline"
but the issue is still here. So it may be a safari mobile change after all
Hello, thanks for answer. Is there anything specific you would like me to check that would help you?
Hello @jakubjereczek, I reproduced the issue on the version 4.0.0, however I don't have the issue in the version 3.33.0 you mentionned. Can you confirm the version you had a bug with ?
Locally on our application I reproduced on 3.33.0/2. But I just checked on https://developers.canal-plus.com/rx-player/ and only 4.0.0 has mentioned issue.
I will try to check if any other initialization settings on our side affect this.
I have made a PR that fixes the issue for version 4 (at least on the device I tested with). I can also backport the fix to version 3.32 so you can test it with your application and let us know if it resolves the issue or not.
@Florent-Bouisset ok, that would be great
After further investigation, I realized that the sequence of creating and disposing RxPlayer instance was wrong in our demo. So we could have at a moment two RxPlayer instances using the same video element (this should not be done).
Maybe your application is doing the same and you have two players using the same video element? I added a dev to check if the video element is already in used by another instance and that throw an error if it's the case.
const myVideo = document.querySelector("video")
new RxPlayer(videoElement)
const player = new Player({ videoElement: myVideo});
const player2 = new Player({ videoElement: myVideo}); // this throw an error "The video element is already attached to another RxPlayer instance."
I created a branch based on v3.32.2 named fix/multiple_player_instance_v3
that include a fix https://github.com/canalplus/rx-player/pull/1393 and the check https://github.com/canalplus/rx-player/pull/1394 , can you try your app with that specific branch? I think you can do that with a npm link.
Let me now if you observe any changes. If you have an error "The video element is already attached to another RxPlayer instance." , you may have to update you application code.
(Sorry a PR merge closed this issue automatically when it shouldn't have, I re-opened it)
I didn't have time to reply, but I'm back. I'll check everything right away.
BTW:
We also noticed a bug in Safari MacOS. For RxPlayer 3.33.0 this time when autoplay: true
hls livestream does not start (LOADED
state is not called). To fix it we reverted to 3.32.1 (the last version on which it works properly).
reproduced on Safari 17.3.1 / MacOS 12.7.3
@Florent-Bouisset I used fix/multiple_player_instance_v3
and created a build to test on my Safari Mobile, but without any differences.
Logs:
(...)
log: "API: current media element state tick" "event" "loadedmetadata" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\nloadedmetadata"
log: "Init: Calculating initial time"
log: "Init: Initial time calculated:" 0
info: "Init: Can begin to play content"
info: "Init: Set initial time" 0
info: "API: Seeking internally" 0
log: "API: current media element state tick" "event" "internal-seeking" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\nseeking"
log: "API: current media element state tick" "event" "seeked" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\nseeked"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
log: "API: current playback timeline:\n\n^0" "\ntimeupdate"
log: "API: current media element state tick" "event" "timeupdate" "position" 0 "seeking" false "internalSeek" null "rebuffering" false "freezing" false "ended" false "paused" true "playbackRate" 1 "readyState" 1
(...)
I didn't receive the The video element is already attached to another RxPlayer instance.
error either.
Hello, thanks for you feedback,
I have made a PR to address the issue you mentioned when having autoplay set to true
.
BTW: We also noticed a bug in Safari MacOS. For RxPlayer 3.33.0 this time when autoplay: true hls livestream does not start (LOADED state is not called). To fix it we reverted to 3.32.1 (the last version on which it works properly). reproduced on Safari 17.3.1 / MacOS 12.7.3
For the issue you had on iOS with autoplay false
, do you have the attribute playsinline
on the video element?
If you have it, the PR https://github.com/canalplus/rx-player/pull/1406 should fix the issue when having attribute playsinline
.
Yes, we have playsinline
property, I will check #1406.
Sorry for late response, I was quite busy. I checked your fix @Florent-Bouisset and now it works - it is possible to play with autoplay: false.
Resolved