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

fragLoadPolicy is not followed if level has 2+ gaps fragments in a row #6682

Open
5 tasks done
zalishchuk opened this issue Sep 6, 2024 · 4 comments
Open
5 tasks done
Labels
Bug GAP segments #EXT-X-GAP support and Fragment.gap usage
Milestone

Comments

@zalishchuk
Copy link

What version of Hls.js are you using?

v1.5.15

What browser (including version) are you using?

Chrome 128.0.6613.114 (Official Build), (arm64)

What OS (including version) are you using?

macOS Sonoma 14.6.1

Test stream

Provided in demo GitHub repository

Configuration

{}

Additional player setup steps

I simplified the demo, but the thing I am trying to achieve here is to make all failed fragments "skippable", so I am trying to set them as a GAP fragment with this code:

hls.on(Hls.Events.ERROR, (event, data) => {
  console.log(event, data);
  if (data.details !== Hls.ErrorDetails.FRAG_LOAD_ERROR) return;
  if (!data.fatal) return;
  console.log('Setting Fragment as a GAP', data.frag);
  data.frag.gap = true;
  data.frag.tagList.unshift(['GAP']);
  hls.startLoad();
});

I want to make Hls.js follow fragLoadPolicy for all requests it does to load fragments, so this code can work properly.

Checklist

Steps to reproduce

  1. Clone demo repository https://github.com/zalishchuk/hlsjs-gap-demo
  2. Run the mock server
  3. Go to http://localhost:3000 to see the described behaviour

Expected behaviour

Fragment requests after gap fragments should follow fragLoadPolicy and make retries, then after all retries are used must pop with fatal FRAG_LOAD_ERROR

What actually happened?

Fragment requests after gap fragments are not following fragLoadPolicy and are not making any retries, so FRAG_LOAD_ERROR never pops

Console output

[log] > Debug logs enabled for "Hls instance" in hls.js version undefined logger.ts:102:16
[log] > stopLoad hls.ts:471:16
[log] > loadSource:http://localhost:3000/public/stream.m3u8 hls.ts:433:16
[log] > [stream-controller]: Trigger BUFFER_RESET stream-controller.ts:574:9
[log] > attachMedia hls.ts:403:16
[log] > [buffer-controller]: created media source: MediaSource buffer-controller.ts:214:11
[log] > [buffer-controller]: Media source opened buffer-controller.ts:1140:9
[log] > [level-controller]: manifest loaded, 1 level(s) found, first bitrate: 0 level-controller.ts:325:13
[log] > [buffer-controller]: 1 bufferCodec event(s) expected buffer-controller.ts:202:9
[log] > startLoad(-1) hls.ts:461:16
[log] > [level-controller]: Switching to level 0 (SDR @0) from level -1 level-controller.ts:420:9
[log] > [stream-controller]: STOPPED->IDLE base-stream-controller.ts:1962:11
[log] > [subtitle-stream-controller]: STOPPED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: Level 0 loaded [0,19][part-19--1], cc [0, 0] duration:60 stream-controller.ts:632:9
[log] > [buffer-controller]: Updating Media Source duration to 60.000 buffer-controller.ts:1015:11
[log] > [stream-controller]: Loading main sn: 0 of level 0 (frag:[0.000-3.000]) cc: 0 [0-19], target: 0 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[log] > injecting Web Worker for "main" transmuxer-interface.ts:88:19
[log] > [transmuxer-interface, main]: Starting new transmux session for sn: 0 p: -1 level: 0 id: 1
        discontinuity: true
        trackSwitch: true
        contiguous: false
        accurateTimeOffset: true
        timeOffset: 0
        initSegmentChange: true transmuxer-interface.ts:238:9
[log] > [stream-controller]: Loaded main sn: 0 of level 0 base-stream-controller.ts:452:15
[log] > Debug logs enabled for "main" in hls.js version undefined eb872f91-c6b2-48ad-ad03-82af3e63c67d:526:19
[log] > [mp4-remuxer]: ISGenerated flag reset transmuxer-interface.ts:394:40
[log] > [mp4-remuxer]: initPTS & initDTS reset transmuxer-interface.ts:394:40
[log] > [mp4-remuxer]: reset next timestamp transmuxer-interface.ts:394:40
[log] > manifest codec:undefined, parsed codec:mp4a.40.2, channels:2, rate:44100 (ADTS object type:2 sampling index:4) eb872f91-c6b2-48ad-ad03-82af3e63c67d:11755:12
[log] > [stream-controller]: FRAG_LOADING->PARSING base-stream-controller.ts:1962:11
[log] > [stream-controller]: Init audio buffer, container:audio/mp4, codecs[selected/level/parsed]=[//mp4a.40.2] stream-controller.ts:1299:11
[log] > [stream-controller]: Init video buffer, container:video/mp4, codecs[level/parsed]=[/avc1.4d401e] stream-controller.ts:1311:11
[log] > [buffer-controller]: 0 bufferCodec event(s) expected audio,video buffer-controller.ts:411:11
[log] > [buffer-controller]: creating sourceBuffer(audio/mp4;codecs=mp4a.40.2) buffer-controller.ts:1089:13
[log] > [buffer-controller]: creating sourceBuffer(video/mp4;codecs=avc1.4d401e) buffer-controller.ts:1089:13
[log] > [audio-stream-controller]: InitPTS for cc: 0 found from main: 131110/90000 audio-stream-controller.ts:139:11
[log] > [transmuxer.ts]: Flushed main sn: 0 of level 0 transmuxer-interface.ts:394:40
[log] > [stream-controller]: PARSING->PARSED base-stream-controller.ts:1962:11
[log] > [stream-controller]: Parsed main sn: 0 of level 0 (frag:[0.000-3.023]) base-stream-controller.ts:1924:9
[log] > [stream-controller]: Buffered main sn: 0 of level 0 (frag:[0.000-3.023] > buffer:[0.023-2.949]) base-stream-controller.ts:639:9
[log] > [stream-controller]: PARSED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loading main sn: 1 of level 0 (frag:[2.949-5.949]) cc: 0 [0-19], target: 2.949 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loaded main sn: 1 of level 0 base-stream-controller.ts:452:15
[log] > [stream-controller]: FRAG_LOADING->PARSING base-stream-controller.ts:1962:11
[log] > [transmuxer.ts]: Flushed main sn: 1 of level 0 transmuxer-interface.ts:394:40
[log] > [stream-controller]: PARSING->PARSED base-stream-controller.ts:1962:11
[log] > [stream-controller]: Parsed main sn: 1 of level 0 (frag:[2.949-6.023]) base-stream-controller.ts:1924:9
[log] > [stream-controller]: Buffered main sn: 1 of level 0 (frag:[2.949-6.023] > buffer:[0.023-5.944]) base-stream-controller.ts:639:9
[log] > [stream-controller]: PARSED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loading main sn: 2 of level 0 (frag:[5.944-8.944]) cc: 0 [0-19], target: 5.944 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loaded main sn: 2 of level 0 base-stream-controller.ts:452:15
[log] > [stream-controller]: FRAG_LOADING->PARSING base-stream-controller.ts:1962:11
[log] > [transmuxer.ts]: Flushed main sn: 2 of level 0 transmuxer-interface.ts:394:40
[log] > [stream-controller]: PARSING->PARSED base-stream-controller.ts:1962:11
[log] > [stream-controller]: Parsed main sn: 2 of level 0 (frag:[5.944-9.023]) base-stream-controller.ts:1924:9
[log] > [stream-controller]: Buffered main sn: 2 of level 0 (frag:[5.944-9.023] > buffer:[0.023-8.963]) base-stream-controller.ts:639:9
[log] > [stream-controller]: PARSED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loading main sn: 3 of level 0 (frag:[8.963-11.963]) cc: 0 [0-19], target: 8.963 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[warn] > [gap-controller]: skipping hole, adjusting currentTime from 0 to 0.1 gap-controller.ts:335:13
[log] > [stream-controller]: media seeking to 0.100, state: FRAG_LOADING base-stream-controller.ts:273:9
[log] > [audio-stream-controller]: media seeking to 0.100, state: STOPPED base-stream-controller.ts:273:9
[log] > [subtitle-stream-controller]: media seeking to 0.100, state: IDLE base-stream-controller.ts:273:9
[log] > [stream-controller]: Media seeked to 0.100 stream-controller.ts:553:11
[log] > [stream-controller]: Loaded main sn: 3 of level 0 base-stream-controller.ts:452:15
[log] > [stream-controller]: FRAG_LOADING->PARSING base-stream-controller.ts:1962:11
[log] > [transmuxer.ts]: Flushed main sn: 3 of level 0 transmuxer-interface.ts:394:40
[log] > [stream-controller]: PARSING->PARSED base-stream-controller.ts:1962:11
[log] > [stream-controller]: Parsed main sn: 3 of level 0 (frag:[8.963-12.023]) base-stream-controller.ts:1924:9
[log] > [stream-controller]: Buffered main sn: 3 of level 0 (frag:[8.963-12.023] > buffer:[0.023-11.958]) base-stream-controller.ts:639:9
[log] > [stream-controller]: PARSED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loading main sn: 4 of level 0 (frag:[11.958-14.958]) cc: 0 [0-19], target: 11.958 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[warn] > [content-steering]: Could not resolve fragGap ("GAP tag found") with content-steering for Pathway: . levels: 1 priorities: ["."] penalized: {".":172} content-steering-controller.ts:220:13
[log] > [stream-controller]: FRAG_LOADING->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loading main sn: 5 of level 0 (frag:[14.958-17.958]) cc: 0 [0-19], target: 14.958 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[warn] > [content-steering]: Could not resolve fragGap ("GAP tag found") with content-steering for Pathway: . levels: 1 priorities: ["."] penalized: {".":172} content-steering-controller.ts:220:13
[log] > [stream-controller]: FRAG_LOADING->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loading main sn: 6 of level 0 (frag:[17.958-20.958]) cc: 0 [0-19], target: 17.958 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[warn] > [content-steering]: Could not resolve fragGap ("GAP tag found") with content-steering for Pathway: . levels: 1 priorities: ["."] penalized: {".":172} content-steering-controller.ts:220:13
[log] > [stream-controller]: FRAG_LOADING->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loading main sn: 7 of level 0 (frag:[20.958-23.958]) cc: 0 [0-19], target: 20.958 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
XHRGET
http://localhost:3000/public/8.ts
[HTTP/1.1 500 Internal Server Error 2ms]

[error] > 500 while loading http://localhost:3000/public/8.ts xhr-loader.ts:251:19
[warn] > [stream-controller]: Fragment 7 of main 0 errored with fragLoadError, retrying loading 1/6 in 1000ms base-stream-controller.ts:1695:11
[log] > [stream-controller]: FRAG_LOADING->FRAG_LOADING_WAITING_RETRY base-stream-controller.ts:1962:11
[log] > [stream-controller]: FRAG_LOADING_WAITING_RETRY->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loading main sn: 8 of level 0 (frag:[23.958-26.958]) cc: 0 [0-19], target: 23.958 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[log] > [transmuxer-interface, main]: Starting new transmux session for sn: 8 p: -1 level: 0 id: 1
        discontinuity: false
        trackSwitch: false
        contiguous: false
        accurateTimeOffset: true
        timeOffset: 23.958276643990885
        initSegmentChange: false transmuxer-interface.ts:238:9
[log] > [stream-controller]: Loaded main sn: 8 of level 0 base-stream-controller.ts:452:15
[log] > [mp4-remuxer]: reset next timestamp transmuxer-interface.ts:394:40
[log] > [stream-controller]: FRAG_LOADING->PARSING base-stream-controller.ts:1962:11
[log] > [transmuxer.ts]: Flushed main sn: 8 of level 0 transmuxer-interface.ts:394:40
[log] > [stream-controller]: PARSING->PARSED base-stream-controller.ts:1962:11
[log] > [stream-controller]: Parsed main sn: 8 of level 0 (frag:[23.963-27.023]) base-stream-controller.ts:1924:9
[log] > [level-controller]: Resetting level error count of 3 on frag buffered level-controller.ts:561:13
[log] > [stream-controller]: Buffered main sn: 8 of level 0 (frag:[23.963-27.023] > buffer:[0.023-11.958][24.023-26.958]) base-stream-controller.ts:639:9
[log] > [stream-controller]: Resetting level fragment error count of 1 on frag buffered base-stream-controller.ts:659:13
[log] > [stream-controller]: PARSED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loading main sn: 9 of level 0 (frag:[26.958-29.958]) cc: 0 [0-19], target: 26.958 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loaded main sn: 9 of level 0 base-stream-controller.ts:452:15
[log] > [stream-controller]: FRAG_LOADING->PARSING base-stream-controller.ts:1962:11
[log] > [transmuxer.ts]: Flushed main sn: 9 of level 0 transmuxer-interface.ts:394:40
[log] > [stream-controller]: PARSING->PARSED base-stream-controller.ts:1962:11
[log] > [stream-controller]: Parsed main sn: 9 of level 0 (frag:[26.958-30.023]) base-stream-controller.ts:1924:9
[log] > [stream-controller]: Buffered main sn: 9 of level 0 (frag:[26.958-30.023] > buffer:[0.023-11.958][24.023-29.954]) base-stream-controller.ts:639:9
[log] > [stream-controller]: PARSED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loading main sn: 10 of level 0 (frag:[29.954-32.954]) cc: 0 [0-19], target: 29.954 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loaded main sn: 10 of level 0 base-stream-controller.ts:452:15
[log] > [stream-controller]: FRAG_LOADING->PARSING base-stream-controller.ts:1962:11
[log] > [transmuxer.ts]: Flushed main sn: 10 of level 0 transmuxer-interface.ts:394:40
[log] > [stream-controller]: PARSING->PARSED base-stream-controller.ts:1962:11
[log] > [stream-controller]: Parsed main sn: 10 of level 0 (frag:[29.954-33.023]) base-stream-controller.ts:1924:9
[log] > [stream-controller]: Buffered main sn: 10 of level 0 (frag:[29.954-33.023] > buffer:[0.023-11.958][24.023-32.949]) base-stream-controller.ts:639:9
[log] > [stream-controller]: PARSED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loading main sn: 11 of level 0 (frag:[32.949-35.949]) cc: 0 [0-19], target: 32.949 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loaded main sn: 11 of level 0 base-stream-controller.ts:452:15
[log] > [stream-controller]: FRAG_LOADING->PARSING base-stream-controller.ts:1962:11
[log] > [transmuxer.ts]: Flushed main sn: 11 of level 0 transmuxer-interface.ts:394:40
[log] > [stream-controller]: PARSING->PARSED base-stream-controller.ts:1962:11
[log] > [stream-controller]: Parsed main sn: 11 of level 0 (frag:[32.949-36.023]) base-stream-controller.ts:1924:9
[log] > [stream-controller]: Buffered main sn: 11 of level 0 (frag:[32.949-36.023] > buffer:[0.023-11.958][24.023-35.944]) base-stream-controller.ts:639:9
[log] > [stream-controller]: PARSED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loading main sn: 12 of level 0 (frag:[35.944-38.944]) cc: 0 [0-19], target: 35.944 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loaded main sn: 12 of level 0 base-stream-controller.ts:452:15
[log] > [stream-controller]: FRAG_LOADING->PARSING base-stream-controller.ts:1962:11
[log] > [transmuxer.ts]: Flushed main sn: 12 of level 0 transmuxer-interface.ts:394:40
[log] > [stream-controller]: PARSING->PARSED base-stream-controller.ts:1962:11
[log] > [stream-controller]: Parsed main sn: 12 of level 0 (frag:[35.944-39.023]) base-stream-controller.ts:1924:9
[log] > [stream-controller]: Buffered main sn: 12 of level 0 (frag:[35.944-39.023] > buffer:[0.023-11.958][24.023-38.963]) base-stream-controller.ts:639:9
[log] > [stream-controller]: PARSED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loading main sn: 13 of level 0 (frag:[38.963-41.963]) cc: 0 [0-19], target: 38.963 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loaded main sn: 13 of level 0 base-stream-controller.ts:452:15
[log] > [stream-controller]: FRAG_LOADING->PARSING base-stream-controller.ts:1962:11
[log] > [transmuxer.ts]: Flushed main sn: 13 of level 0 transmuxer-interface.ts:394:40
[log] > [stream-controller]: PARSING->PARSED base-stream-controller.ts:1962:11
[log] > [stream-controller]: Parsed main sn: 13 of level 0 (frag:[38.963-42.023]) base-stream-controller.ts:1924:9
[log] > [stream-controller]: Buffered main sn: 13 of level 0 (frag:[38.963-42.023] > buffer:[0.023-11.958][24.023-41.958]) base-stream-controller.ts:639:9
[log] > [stream-controller]: PARSED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loading main sn: 14 of level 0 (frag:[41.958-44.958]) cc: 0 [0-19], target: 41.958 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loaded main sn: 14 of level 0 base-stream-controller.ts:452:15
[log] > [stream-controller]: FRAG_LOADING->PARSING base-stream-controller.ts:1962:11
[log] > [transmuxer.ts]: Flushed main sn: 14 of level 0 transmuxer-interface.ts:394:40
[log] > [stream-controller]: PARSING->PARSED base-stream-controller.ts:1962:11
[log] > [stream-controller]: Parsed main sn: 14 of level 0 (frag:[41.958-45.023]) base-stream-controller.ts:1924:9
[log] > [stream-controller]: Buffered main sn: 14 of level 0 (frag:[41.958-45.023] > buffer:[0.023-11.958][24.023-44.954]) base-stream-controller.ts:639:9
[log] > [stream-controller]: PARSED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: buffer full after gaps in "main" playlist starting at sn: 15 base-stream-controller.ts:1289:17
[log] > [stream-controller]: Loading main sn: 15 of level 0 (frag:[44.954-47.954]) cc: 0 [0-19], target: 44.954 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loaded main sn: 15 of level 0 base-stream-controller.ts:452:15
[log] > [stream-controller]: FRAG_LOADING->PARSING base-stream-controller.ts:1962:11
[log] > [transmuxer.ts]: Flushed main sn: 15 of level 0 transmuxer-interface.ts:394:40
[log] > [stream-controller]: PARSING->PARSED base-stream-controller.ts:1962:11
[log] > [stream-controller]: Parsed main sn: 15 of level 0 (frag:[44.954-48.023]) base-stream-controller.ts:1924:9
[log] > [stream-controller]: Buffered main sn: 15 of level 0 (frag:[44.954-48.023] > buffer:[0.023-11.958][24.023-47.949]) base-stream-controller.ts:639:9
[log] > [stream-controller]: PARSED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: buffer full after gaps in "main" playlist starting at sn: 16 base-stream-controller.ts:1289:17
[log] > [stream-controller]: Loading main sn: 16 of level 0 (frag:[47.949-50.949]) cc: 0 [0-19], target: 47.949 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loaded main sn: 16 of level 0 base-stream-controller.ts:452:15
[log] > [stream-controller]: FRAG_LOADING->PARSING base-stream-controller.ts:1962:11
[log] > [transmuxer.ts]: Flushed main sn: 16 of level 0 transmuxer-interface.ts:394:40
[log] > [stream-controller]: PARSING->PARSED base-stream-controller.ts:1962:11
[log] > [stream-controller]: Parsed main sn: 16 of level 0 (frag:[47.949-51.023]) base-stream-controller.ts:1924:9
[log] > [stream-controller]: Buffered main sn: 16 of level 0 (frag:[47.949-51.023] > buffer:[0.023-11.958][24.023-50.945]) base-stream-controller.ts:639:9
[log] > [stream-controller]: PARSED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: buffer full after gaps in "main" playlist starting at sn: 17 base-stream-controller.ts:1289:17
[log] > [stream-controller]: Loading main sn: 17 of level 0 (frag:[50.945-53.945]) cc: 0 [0-19], target: 50.945 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loaded main sn: 17 of level 0 base-stream-controller.ts:452:15
[log] > [stream-controller]: FRAG_LOADING->PARSING base-stream-controller.ts:1962:11
[log] > [transmuxer.ts]: Flushed main sn: 17 of level 0 transmuxer-interface.ts:394:40
[log] > [stream-controller]: PARSING->PARSED base-stream-controller.ts:1962:11
[log] > [stream-controller]: Parsed main sn: 17 of level 0 (frag:[50.945-54.023]) base-stream-controller.ts:1924:9
[log] > [stream-controller]: Buffered main sn: 17 of level 0 (frag:[50.945-54.023] > buffer:[0.023-11.958][24.023-53.963]) base-stream-controller.ts:639:9
[log] > [stream-controller]: PARSED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: buffer full after gaps in "main" playlist starting at sn: 18 base-stream-controller.ts:1289:17
[log] > [stream-controller]: Loading main sn: 18 of level 0 (frag:[53.963-56.963]) cc: 0 [0-19], target: 53.963 base-stream-controller.ts:847:9
[log] > [stream-controller]: IDLE->FRAG_LOADING base-stream-controller.ts:1962:11
[log] > [stream-controller]: Loaded main sn: 18 of level 0 base-stream-controller.ts:452:15
[log] > [stream-controller]: FRAG_LOADING->PARSING base-stream-controller.ts:1962:11
[log] > [transmuxer.ts]: Flushed main sn: 18 of level 0 transmuxer-interface.ts:394:40
[log] > [stream-controller]: PARSING->PARSED base-stream-controller.ts:1962:11
[log] > [stream-controller]: Parsed main sn: 18 of level 0 (frag:[53.963-57.023]) base-stream-controller.ts:1924:9
[log] > [stream-controller]: Buffered main sn: 18 of level 0 (frag:[53.963-57.023] > buffer:[0.023-11.958][24.023-56.959]) base-stream-controller.ts:639:9
[log] > [stream-controller]: PARSED->IDLE base-stream-controller.ts:1962:11
[log] > [stream-controller]: buffer full after gaps in "main" playlist starting at sn: 19 base-stream-controller.ts:1289:17
[warn] > [gap-controller]: Playback stalling at @11.960378 due to low buffer ({"len":0,"start":11.960378,"end":11.960378,"nextStart":24.023222}) gap-controller.ts:260:11

Chrome media internals output

No response

@zalishchuk zalishchuk added Bug Needs Triage If there is a suspected stream issue, apply this label to triage if it is something we should fix. labels Sep 6, 2024
@robwalch robwalch added this to the 1.6.0 milestone Nov 18, 2024
@robwalch robwalch added GAP segments #EXT-X-GAP support and Fragment.gap usage and removed Needs Triage If there is a suspected stream issue, apply this label to triage if it is something we should fix. labels Jan 4, 2025
@robwalch
Copy link
Collaborator

robwalch commented Jan 4, 2025

I simplified the demo, but the thing I am trying to achieve here is to make all failed fragments "skippable", so I am trying to
if (data.details !== Hls.ErrorDetails.FRAG_LOAD_ERROR) return;
if (!data.fatal) return;

So you want to run through all retries for FRAG_LOAD_ERROR until fatal then mark the fragment as a gap and restart loading? While you can call startLoad after a fatal error, fatal means fatal. You blew it. You should not use that player any more.

I would suggest configuring HLS.js with a much higher retry count than the default of 6, and then in your application add a gap after the number of retries you want before treating it as a gap (something reasonable like 3).

@robwalch
Copy link
Collaborator

robwalch commented Jan 4, 2025

Clone demo repository https://github.com/zalishchuk/hlsjs-gap-demo

Have you tried running the app against v1.6.0-beta.2 or latest dev?

@zalishchuk
Copy link
Author

zalishchuk commented Jan 4, 2025

@robwalch I apologize for being a bit out of the loop since this issue happened a while ago, but I still consider it a backlog item for myself. I've done some testing with v1.6.0-beta.2, and while it looks promising, there are still some imperfections with the errored adjacent fragments.

Test Cases:

Note

When a fragment is checked, it means it’s available. If unchecked, though, it indicates that the fragment isn’t currently accessible due to a 500 Server Error.

1. Unavailable Adjacent Fragments

  • 1.ts
  • 2.ts
  • 3.ts
  • 4.ts
  • 5.ts
  • 6.ts
  • 7.ts
  • 8.ts

The result here is that fragment 3.ts will follow the retry policies we've put in place, but when it runs out of retries, HLS.js will run over fragments 4.ts, 5.ts, and 6.ts without making any attempts to retry. I want to avoid this, as I’d prefer to apply retry policies no matter how many fragment errors I have at the moment. The latest HLS.js beta build automatically handles failed fragments gapping without needing custom event handlers or complicated code. It’s working just how I initially wanted it to, which is fantastic!

Document 2025-01-04 at 5 29 55 AM

2. Unavailable Every Other Fragment

  • 1.ts
  • 2.ts
  • 3.ts
  • 4.ts
  • 5.ts
  • 6.ts
  • 7.ts
  • 8.ts

In this case, HLS.js will apply retry policies to any unavailable fragments, which perfectly aligns with my goal. A certain variable, likely the Level Fragment Errors count, appears to get reset only after a successful fragment load.

Document 2025-01-04 at 5 33 01 AM

My Hls.js Config:
I've just made a small adjustment by reducing the number of maximum error retries to 3.

{
  fragLoadPolicy: {
    default: {
      maxTimeToFirstByteMs: 10000,
      maxLoadTimeMs: 120000,
      timeoutRetry: {
        maxNumRetry: 4,
        retryDelayMs: 0,
        maxRetryDelayMs: 0,
      },
      errorRetry: {
        maxNumRetry: 3,
        retryDelayMs: 1000,
        maxRetryDelayMs: 8000,
      },
    },
  },
}

Would it be possible to apply the same approach to the nearby fragments? This would completely address my question, and the best part is that there’s no need for any custom code! Everything is running smoothly now, and HLS.js handles seamlessly skipping over any failed fragments. I still find myself grappling with the issue of how HLS.js tends to panic and overlook retry policies when searching for the next fragment after fragment error.

@robwalch
Copy link
Collaborator

robwalch commented Jan 4, 2025

A certain variable, likely the Level Fragment Errors count, appears to get reset only after a successful fragment load.

Would it be possible to apply the same approach to the nearby fragments?

Level error counts are there so that an alternate will be selected rather than retrying all fragments multiple times for the entire playlist. I suppose if you restart loading after a fatal error, then that count should be reset so that retries honor the retry count again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug GAP segments #EXT-X-GAP support and Fragment.gap usage
Projects
Development

No branches or pull requests

2 participants