Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infinity loading state on Safari Mobile when autoplay is false #1390

Closed
jakubjereczek opened this issue Feb 23, 2024 · 17 comments · Fixed by #1393
Closed

Infinity loading state on Safari Mobile when autoplay is false #1390

jakubjereczek opened this issue Feb 23, 2024 · 17 comments · Fixed by #1393

Comments

@jakubjereczek
Copy link

jakubjereczek commented Feb 23, 2024

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

(...)
@jakubjereczek
Copy link
Author

jakubjereczek commented Feb 23, 2024

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.
image

@peaBerberian
Copy link
Collaborator

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.

@peaBerberian
Copy link
Collaborator

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.

@peaBerberian
Copy link
Collaborator

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

peaBerberian added a commit that referenced this issue Feb 26, 2024
… state

Fixes #1390

We previously had a work-around specific to safari mobile when the
media element had the `playsinline` attribute where the browser would
never switch to the `LOADED` state if the media element was still in a
`paused` state.

From a recent issue (#1390), it seems to now even happen when
`playsinline` is not set.

We also add a check for whether the media element is `paused` (as if not
paused, such as when autoplay was handled, there doesn't seem to be any
issue).

It shouldn't break the previous seen case if we are to believe the
comment on top of the work-around.
peaBerberian added a commit that referenced this issue Feb 26, 2024
… state

Fixes #1390

We previously had a work-around specific to safari mobile when the
media element had the `playsinline` attribute where the browser would
never switch to the `LOADED` state if the media element was still in a
`paused` state.

From a recent issue (#1390), it seems to now even happen when
`playsinline` is not set.

We also add a check for whether the media element is `paused` (as if not
paused, such as when autoplay was handled, there doesn't seem to be any
issue).

It shouldn't break the previous seen case if we are to believe the
comment on top of the work-around.
@jakubjereczek
Copy link
Author

Hello, thanks for answer.
Is there anything specific you would like me to check that would help you?

@Florent-Bouisset
Copy link
Collaborator

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 ?

@jakubjereczek
Copy link
Author

jakubjereczek commented Feb 27, 2024

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.

@Florent-Bouisset
Copy link
Collaborator

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.

@jakubjereczek
Copy link
Author

@Florent-Bouisset ok, that would be great

@Florent-Bouisset
Copy link
Collaborator

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 #1393 and the check #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.

@peaBerberian
Copy link
Collaborator

(Sorry a PR merge closed this issue automatically when it shouldn't have, I re-opened it)

@jakubjereczek
Copy link
Author

jakubjereczek commented Mar 13, 2024

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

@jakubjereczek
Copy link
Author

@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.

@Florent-Bouisset
Copy link
Collaborator

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 #1406 should fix the issue when having attribute playsinline.

@jakubjereczek
Copy link
Author

Yes, we have playsinline property, I will check #1406.

@jakubjereczek
Copy link
Author

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.

@jakubjereczek
Copy link
Author

Resolved

This was referenced Jun 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants