fix: handle page restoration from bfcache in Safari#7683
fix: handle page restoration from bfcache in Safari#7683robwalch merged 3 commits intovideo-dev:masterfrom
Conversation
|
I don't think we should apply this to all instances and browsers. The buffer controller would be the appropriate place to handle premature closing of the MediaSource, with recoverMediaError handling the detach/attach and loading. The source should not be reset in browsers that do not display this issue anywhere the MediaSource remains open. It's also concerning that we're adding a global listener and never removing it. All listeners should be removed when instances are destroyed. |
|
Thanks, @robwalch. Appreciate the feedback on the initial approach. I didn't realize I've removed the global listener, for |
| const handler = this._handleSafariMediaSourceClose.bind(this); | ||
| this.safariSourceCloseHandler = handler; |
There was a problem hiding this comment.
This binding is unnecessary with arrow function properties. private _handleSafariMediaSourceClose = () => will always be involved with the current class instance context for "this". (See other examples in the project like private onMediaSeeked = () =>.)
| data: MediaAttachingData, | ||
| ) { | ||
| const media = (this.media = data.media); | ||
| this.needsMediaSourceCloseRecovery = this.detectMediaSourceCloseIssue(); |
There was a problem hiding this comment.
Sorry, I didn't mean to suggest that this should be behind a user-agent check. I'd prefer to use existing listeners, or only add new event listeners (like "pageshow") as needed to detect that the source closure resulted from backgrounding the page.
We already have a listener for 'sourceclose': _onMediaSourceClose >
- Can we simply use that to reopen when media is still attached and the player is not being destroyed?
- Are there any other conditions that should be considered, like
video.error, hls error, or loading state? - When is the MediaSource closed in relation to the page being backgrounded when the browser bug presents?
There was a problem hiding this comment.
Ah, sorry for the misunderstanding! I think we have two solid options here.
- We can use the existing
sourcecloselistener /_onMediaSourceClosehandler. On Safari, the MediaSource is closed when returning to the page via bfcache, so thesourcecloseevent fires immediately when we land back on the page. When this occurs, there's also a media error ("Load was aborted"), but I don't think that error is specific to this issue.
If media is still attached when sourceclose fires, we can trigger recovery. My only concern is understanding all scenarios where sourceclose may fire. Currently, the event also fires during media detachment, but we don't catch it because we remove the listener before the event is captured.
Something like this works:
private _onMediaSourceClose = () => {
if (this.media) {
this.hls.recoverMediaError();
}
};My concern is: what happens if we start catching the sourceclose event during media detachment in the future? I think we would try to trigger a recovery? But then again, this.media would be null, so the condition here probably protects us from this.
- We can add the
pageshowlistener from earlier to specifically account for bfcache restoration:
private _onPageShow = (event: PageTransitionEvent) => {
if (event.persisted && this.mediaSource?.readyState === 'closed' && this.media) {
this.hls.recoverMediaError();
}
};This is more explicit about handling bfcache restoration. On other browsers, the MediaSource readyState remains open when restoring from bfcache, so this check would prevent unnecessary recovery attempts. However, we would be adding a global window listener to all browsers and instances.
I pushed up a change for option 1, but happy to continue discussing.
7931295 to
a7e5d32
Compare
a7e5d32 to
4d10367
Compare
|
Hi @christriants. Any chance you could verify whether or not these changes also address #7687? It sounds like the same root cause but with different repro steps on iOS. I confirmed that issue but haven't staged a build for testing. |
|
This also significantly affects iOS in-app browsers such as Facebook or Instagram. Is there any workaround I can apply now to prevent playback issues and errors? |
Hi @zalishchuk. You could always workaround this issue by calling
|
|
@christriants The issue consistently occurs in Safari on iOS 26.2 when you clear the cache and load the page. Sometimes, playback gets stuck because it waits for 3 failed buffer appends by default. However, it occasionally triggers 3 failed appends and then shows a fatal error. Behaves very strangely, to be honest. stuck log: fatal log: |
You need to call
What is fatal about it? There are no errors in the logs. This and the previous comments related to #7687 should be included in that issue. |
This PR will...
This PR fixes an issue where video playback fails to resume after navigating back and forth between pages in Safari. The problem manifests as buffer append errors when reinitializing the player after a page navigation.
Why is this Pull Request needed?
The issue affects users who navigate away from a page with a playing HLS.js video and then return to it on Safari.
Are there any points in the code the reviewer needs to double check?
Resolves issues:
Fixes #7578 - Unable to resume video playback after navigating back and forth between two pages
Demo of issue:
https://github.com/user-attachments/assets/d87ab24b-9774-474a-bbc1-a096d4d70009
Demo of fix:
Screen.Recording.2026-01-05.at.6.35.50.PM.mov
Checklist