Open Alibirb opened 1 year ago
The logs do not show any attempt made to seek. Please include logs from v1.2.9 that cover the description under "What actually happened?"
The player is setup to retry fragment loading. It does and when all attempts fail and there is no other level to switch to, the error is escalated to fatal. You would need to seek before that point. In the latest release, the player may not retry on 4xx errors since most often the result will be the same.
The HLS spec recommends a GAP tag for segments that should not be loaded. With support for GAP tags the player would attempt a switch or jump gaps.
Sorry, the first log I tried to attach exceeded the character limit, so it wouldn't let me post it, so I reloaded the page and copied the fresh log. I'll see if I can post another log showing attempts to seek after work.
The player is set to try to recover from media errors, even fatal ones. This works when the failed segment is in the middle of the playlist, but when it's the first segment, it never tries to load any other segments.
The EXT-X-GAP
tag, as I understand it, is to indicate that there's a gap with no media. Wouldn't applying it to my segments make the player simply skip them all, even when the segments actually are available?
The player is set to try to recover from media errors, even fatal ones.
There's no in-player recovery from fatal errors. You can instantiate a new player instance and reload the stream - maybe with a new startPosition
to skip the first segment.
The EXT-X-GAP tag, as I understand it, is to indicate that there's a gap with no media. Wouldn't applying it to my segments make the player simply skip them all, even when the segments actually are available?
If the segment 404s it is not available. Ideally you would not publish segments in the playlist that are not available. A GAP tag is a way to tell clients not to load something that you know is incomplete or unavailable. Each GAP tag only applies to one segment.
I'll see if I can post another log showing attempts to seek after work.
Please do so with the latest version. Including seek attempts and all logs up to fatal error or end will help us see what is actually happening, where there are bugs, and where we could make improvements.
This works when the failed segment is in the middle of the playlist, but when it's the first segment, it never tries to load any other segments.
The gap controller can skip up to 2 seconds to begin playback if media is buffered. It will not skip large gaps if playback hasn't started and playback cannot start if the first segment cannot be loaded.
There's no in-player recovery from fatal errors. You can instantiate a new player instance and reload the stream - maybe with a new startPosition to skip the first segment.
Technically, it's not the player, but the demo page does have logic to try to recover from certain "fatal" errors. I'll have to try the startPosition setting. That sounds like it should do the trick.
If the segment 404s it is not available. Ideally you would not publish segments in the playlist that are not available. A GAP tag is a way to tell clients not to load something that you know is incomplete or unavailable. Each GAP tag only applies to one segment.
That's what I thought. I understand that obviously if I KNOW the segment isn't available, I shouldn't be telling clients to use it, but unfortunately things can get messed up, and I want the client to be able to handle basic errors like this as gracefully as possible.
The gap controller can skip up to 2 seconds to begin playback if media is buffered. It will not skip large gaps if playback hasn't started and playback cannot start if the first segment cannot be loaded.
If I'm understanding you correctly, it sounds like the behavior I'm seeing is intentional. The gap controller intentionally limits the initial gap to 2 seconds, while allowing longer gaps in the middle of playback. So if my 10 second initial segment is missing, the player deliberately refuses to skip the gap, whereas it would skip the gap if it occurred in the middle of the stream? Why does it enforce this restriction?
Edited description with new log, where I tried to seek, as well as hit the "Recover media-error" button a few times.
There's no in-player recovery from fatal errors. You can instantiate a new player instance and reload the stream - maybe with a new
startPosition
to skip the first segment.
Setting startPosition
to 10
to skip the first segment does get the video to play. So I should be able to write some error-handling logic in my application to retry with different start positions if it fails to load. Thank you!
Thanks for the logs. The player is retrying up to fragLoadingMaxRetry
, increasing the delay between retries based on fragLoadingRetryDelay
up to fragLoadingMaxRetryTimeout
:
https://github.com/video-dev/hls.js/blob/52653655698d3eb0d9920170b71a2bd4867ed5ca/src/controller/base-stream-controller.ts#L1350
I can reproduce and finally get the fatal error after the last attempt fails (by network blocking the first segment in a single variant playlist, I get all the same logs up to this point and then a final fatal error that stops the player):
hls.js:2890 [warn] > [stream-controller]: Fragment 0 of main 0 failed to load, retrying in 32000ms
hls.js:2999 [log] > [stream-controller]: FRAG_LOADING->FRAG_LOADING_WAITING_RETRY
hls-demo.js:41531 Error event:
{type: 'networkError', details: 'fragLoadError', fatal: false, frag: Fragment, response: {…}, …}
hls.js:8196 [log] > [stream-controller]: retryDate reached, switch back to IDLE state
hls.js:2999 [log] > [stream-controller]: FRAG_LOADING_WAITING_RETRY->IDLE
hls.js:2380 [log] > [stream-controller]: Loading fragment 0 cc: 0 of [0-63] level: 0, target: 0
hls.js:2999 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.js:26252 [error] > 0 while loading https://test-streams.mux.dev/x36xhzz/url_6/url_846/193039199_mp4_h264_aac_hq_7.ts
hls.js:2904 [error] > fragLoadError reaches max retry, redispatch as fatal ...
hls.js:15608 [log] > stopLoad
hls.js:2999 [log] > [stream-controller]: FRAG_LOADING->STOPPED
hls.js:2999 [log] > [subtitle-stream-controller]: IDLE->STOPPED
hls.js:2999 [log] > [stream-controller]: STOPPED->ERROR
hls.js:2999 [log] > [audio-stream-controller]: STOPPED->ERROR
hls-demo.js:41531 Error event:
{type: 'networkError', details: 'fragLoadError', fatal: true, frag: Fragment, response: {…}, …}
This is expected. To handle the loading error quickly and shift loading to a new time, use hls.startLoad(10)
(or whatever time you want to start loading at).
~Bug Confirmed:~
Seeking is ignored and I did not expect that to be the case. Thanks for bringing this to my attention. It looks like the HTMLMediaElement's seeking
event does not fire in this state (before playback / no media / readyState: 0).
HLS.js ignores currentTime
intentionally prior to anything being loaded. This is so that it honors startPosition
and/or seeks to the live edge in live streams. So I'll have to think about what event(s) should make the player adjust the internal nextLoadPosition
to a new currentTime
and away from startPosition
. I'm not sure it should as the content is not being served correctly. I think using the API to workaround this kind of issue is best. We should not have the player seek on its own (without signals like GAP tags) as this could make the player request all the segments in an expired playlist rather than failing fast as it should. Using currentTime before playback has begun could present new issues for valid streams.
I've discovered that I actually need to set both startPosition
and currentTime
when reloading in order to work around this properly. Upon initial page load, just calling startLoad()
with a startPosition
on error gets the stream going, but once it's playing, if you seek back to the beginning, it seems like startPosition
gets ignored in favor of currentTime
(it keeps trying to load that first segment). Setting both seems to do the trick.
Let me know if #6171 resolves the issue for you. I think the option of skipping segments that fail to reload should be behind a config option. See the PR description and please provide feedback.
What version of Hls.js are you using?
master
What browser (including version) are you using?
Firefox 108.0.1 and Chromium 108.0.5359.124
What OS (including version) are you using?
Manjaro
Test stream
No response
Configuration
Additional player setup steps
Sorry for the lack of test stream; I'm seeing this on some surveillance footage of my house, which I don't really want to make externally accessible. I tried to find a test stream that uses separate TS files for each segment, but couldn't find any. If anyone knows of one, you should be able to just edit the first entry of the manifest to have an incorrect filename so it gives a 404, and then this error should pop up.
I also can't actually test it with the regular netlify-hosted demos, because my stream is only served over HTTP, not HTTPS, and even with CORS, the browser doesn't allow accessing HTTP content from an HTTPS page. But I checked out both
master
and1.2.9
and ran the demo app locally over HTTP, and verified the behavior is the same.The stream was created with this command:
ffmpeg -loglevel warning -rtsp_transport tcp -i rtsp://MY_CAMERA:554/ -strftime 1 -c copy -flags +cgop -g 30 -hls_time 10 -hls_list_size 60480 -hls_flags append_list+delete_segments /var/recordings/1/1/combined.m3u8
Checklist
Steps to reproduce
Expected behaviour
Player should play the first working segment, or at least allow to seek to a working segment. This is how it works if the missing segment is in the MIDDLE of the playlist, but not when it's the first segment.
What actually happened?
Player will not play anything at all. On Firefox, it shows the video as being 0 seconds. Chromium shows the correct time, and allows to TRY to seek, but no matter where you seek to, it won't play.
Console output
Chrome media internals output
No response