Repository navigation
Introduce MEDIA_SOURCE_REQUIRES_RESET error event (MediaSource closed while attached or ended on append error) - #7699
Conversation
There was a problem hiding this comment.
Hi @christriants. Thanks for following up with this PR. We need to process this work in order and coordinate changes with @zalishchuk. I'd like to merge these PRs in the following order:
#7693 is merged and resolves recoverMediaError not restarting network requests when autoStartLoad is disabled.
#7697 will circuit append error handling when it detects that Safari put the MediaSource in an "ended" state. Ideally, this change would also emit the error you are introducing here, with a different error message. This PR should actually remove the handling of MediaSource readyState: ended/.test(data.error.message) in error-controller (review feedback pending).
#7699 (this PR) introduces a new error and manages recovery by calling recoverMediaError in the error controller. We do not want this in the NetworkErrorAction.SendAlternateToPenaltyBox block, as that block is meant to handle what happens after switching, and append retries have been exhausted. We probably want a new action for "requires reset" errors, but this should probably be discussed with whoever is doing and testing the implementation.
| case NetworkErrorAction.SendAlternateToPenaltyBox: { | ||
| this.sendAlternateToPenaltyBox(data); | ||
| const msg = data.error?.message || ''; | ||
| const isMediaSourceEnded = /MediaSource readyState: ended/.test(msg); | ||
| const isMediaSourceClosed = | ||
| data.details === ErrorDetails.MEDIA_SOURCE_CLOSED_UNEXPECTEDLY; | ||
| if ( | ||
| !data.errorAction.resolved && | ||
| data.details !== ErrorDetails.FRAG_GAP | ||
| ) { | ||
| data.fatal = true; | ||
| } else if (/MediaSource readyState: ended/.test(data.error.message)) { | ||
| this.warn( | ||
| `MediaSource ended after "${data.sourceBufferName}" sourceBuffer append error. Attempting to recover from media error.`, | ||
| ); | ||
| } | ||
| if (isMediaSourceEnded || isMediaSourceClosed) { | ||
| if (isMediaSourceEnded) { | ||
| this.warn( | ||
| `MediaSource ended after "${data.sourceBufferName}" sourceBuffer append error. Attempting to recover from media error.`, | ||
| ); | ||
| } else { | ||
| this.warn( | ||
| `MediaSource closed unexpectedly while media was attached (${data.sourceBufferName}). Attempting to recover from media error.`, | ||
| ); | ||
| } | ||
| this.hls.recoverMediaError(); | ||
| } | ||
| break; | ||
| } |
There was a problem hiding this comment.
With #7697, or as a follow-up, that should also emit the new error event. How is the new error getting assigned SendAlternateToPenaltyBox? Is it?
My advice would be to remove this block of changes and wait for #7697 to be merged. Coordinate with @zalishchuk on removal of the /MediaSource readyState: ended/.test(msg) test. With this PR, the new error being defined should replace that test, since the error event itself has a description signalling that a reset is required.
| // Triggered when MediaSource is closed while media is still attached | ||
| MEDIA_SOURCE_CLOSED_UNEXPECTEDLY = 'mediaSourceClosedUnexpectedly', |
There was a problem hiding this comment.
Can we make this more generic so it covers any error that requires a MediaSource reset?
I'd also like it to cover the "ended" state issue described in #7697. I was thinking MEDIA_SOURCE_REQUIRES_RESET. The specific details could be included in the event's error message.
|
Hi @christriants. #7697 has been merged. Let me know if you can rebase and take it from here. Thanks! |
dbbf972 to
068140e
Compare
|
I found a case where we Penalizing/switching to a supported variant would resolve the issue. Making the error fatal after and not calling recoveryMediaError after the max append error count is also necessary in case there are no alternate codec variants. cc #7697 |
38b85d9 to
5236d37
Compare
5236d37 to
c08c23c
Compare
|
Can this be deployed to CF Pages to see how it performs in a real-world scenario? |
MEDIA_SOURCE_REQUIRES_RESET error event (MediaSource closed while attached or ended on append error)
|
Taking the change as-is. You can test and provide feedback using https://hlsjs-dev.video-dev.org/demo/. I'll comment again with some follow-up work for #7535. After some reconsideration, we should always emit the appending/append error events. This involves a little backtracking on #7697, but ultimately, we'll have consistent behavior when appending is not possible, or an append fails, and we should limit recovery attempts following sb update errors using the configured |
With #7702 the appending error is back, but it will be followed by a source reset error. This event sequence is similar to buffer full errors. It is a bit odd that two errors are emitted at once, but I am choosing to maintain this order in case folks use it for reporting purposes. Chrome also goes through the same path with readyState “ended” when it fails to parse the media. If anyone can suggest ways to differentiate those Chrome pipeline errors from the Safari platform exception, then we can differentiate the error handling slightly, but we should leave the appending error. It should be safe to ignore. Please see and comment on #7702 now that this PR is merged. |
* Handle `MEDIA_SOURCE_REQUIRES_RESET` with variant switch, switch to SDR, and reset media source error action and flags Fixes #7535 with unsupported HLG only variants Follow-up to #7699 and #7697 * Do not recover from MediaSource close while attached following fatal append error * Add media error event logging Related to #7116 * Use add/remove event listener helpers in buffer-controller
…-dev#7702) * Handle `MEDIA_SOURCE_REQUIRES_RESET` with variant switch, switch to SDR, and reset media source error action and flags Fixes video-dev#7535 with unsupported HLG only variants Follow-up to video-dev#7699 and video-dev#7697 * Do not recover from MediaSource close while attached following fatal append error * Add media error event logging Related to video-dev#7116 * Use add/remove event listener helpers in buffer-controller

This PR will...
Refactor the MediaSource close handler to emit a new error event instead of directly calling recovery, allowing applications to intercept and handle the error before automatic recovery occurs.
Changes:
MEDIA_SOURCE_REQUIRES_RESETerror when MediaSource closes unexpectedlyMEDIA_SOURCE_REQUIRES_RESETerror from SourceBuffer update error when MediaSource is endedonErrorOutand callsrecoverMediaError()if neededErrorDetails.MEDIA_SOURCE_REQUIRES_RESETWhy is this Pull Request needed?
When MediaSource closes unexpectedly with media attached (on Safari bfcache restore), the buffer controller directly calls
this.hls.recoverMediaError(), bypassing the normal error handling flow. This change allows the media to recover through the full error handling route, whererecoverMediaErrorwould end up getting called in error-controller, instead of directly in buffer-controller.Resolves issues:
N/A - This is a refactor, not fixing a specific reported bug. Related discussion in #7693 (comment): #7693 (comment), and a follow-up to #7683
Manual testing:
MEDIA_SOURCE_REQUIRES_RESETerror is loggedChecklist