Repository navigation
Do not recover a media error that is already fatal - #3
Closed
hongjun-bae wants to merge 1 commit into
Closed
hongjun-bae wants to merge 1 commit into
hongjun-bae wants to merge 1 commit into
Conversation
`onErrorOut` calls `recoverMediaError()` whenever the error action carries `ErrorActionFlags.ResetMediaSource`, then calls `stopLoad()` on the next line when the error is fatal. The two undo each other. `recoverMediaError()` detaches and re-attaches the media, and calls `startLoad(time)` when loading had started (hls.ts). The re-attach is asynchronous, so the `MEDIA_ATTACHED` handler in `base-stream-controller` runs after the synchronous `stopLoad()` and starts loading again while `autoStartLoad` is set, which is the default. The player keeps requesting the segment the SourceBuffer rejected after it has told the application the error is fatal. On a single variant stream this is a loop. `MEDIA_SOURCE_REQUIRES_RESET` has no alternate level to switch to, so `errorAction.resolved` stays false and every rejection is promoted to fatal in the branch above. Measured on a fork of the v1.6 line with the reset backported: nine self recoveries, nine fatal errors delivered to the application and nine refusals by its own recovery, one per cycle. Before video-dev#7702 the two were mutually exclusive: if (!resolved && details !== FRAG_GAP) data.fatal = true; else if (/MediaSource readyState: ended/.test(data.error.message)) recoverMediaError(); Restore that by skipping the reset once the error is fatal. Recovery of a fatal error belongs to the application. Non fatal paths are unchanged. The existing unit test covered the no alternate case, where the error is promoted to fatal before the flag is read. It is replaced by two tests, one for each side of the condition.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR will...
Stop
onErrorOutfrom callingrecoverMediaError()for an error it is about to treat as fatal.Why is this Pull Request needed?
onErrorOutruns both branches in the same pass:recoverMediaError()detaches and re-attaches the media and callsstartLoad(time)when loading had started. The re-attach is asynchronous, soBaseStreamController.onMediaAttachedruns after the synchronousstopLoad()and starts loading again whileautoStartLoadis set, which is the default. The player keeps requesting the segment the SourceBuffer rejected after it has told the application the error is fatal.On a single variant stream this becomes a loop.
MEDIA_SOURCE_REQUIRES_RESEThas no alternate level to switch to, soerrorAction.resolvedstays false, every rejection is promoted to fatal in the branch above, and the flag check restarts it. Measured on a fork of the v1.6 line with video-dev#7699, video-dev#7702 and video-dev#7707 backported, one deliberately corrupted fMP4 segment on a live single variant stream: nine self recoveries, nine fatal errors delivered to the application, nine refusals by the application's own recovery, one of each per cycle.Before video-dev#7702 the two were mutually exclusive:
This restores that: recovery of a fatal error belongs to the application. Non fatal paths are unchanged, so a
MEDIA_SOURCE_REQUIRES_RESETthat a level switch resolves still resets the MediaSource.Related to video-dev#8035. It is independent of video-dev#8045, which decides whether the fragment is skipped; this decides only what happens once an error is already fatal.
Are there any points in the code the reviewer needs to double check?
The existing unit test
treats MEDIA_SOURCE_REQUIRES_RESET as recoverable and calls recoverMediaErrorcovered the no-alternate case, whereonErrorOutpromotes the error to fatal before the flag is read. It is replaced by two tests, one per side of the condition:recoverMediaError()stopLoad()is calledIf the intent was that a fatal
MEDIA_SOURCE_REQUIRES_RESETshould still rebuild the MediaSource, the fix belongs on the other side instead:stopLoad()would have to survive the re-attach. Happy to reshape it that way.Resolves issues:
Related to video-dev#8035
Checklist