hls.js
hls.js copied to clipboard
Fix m3u8 does not reload properly in low latency mode which causes buffer stalled
This fix move to use partTarget as reference for m3u8 reload interval if the low latency mode is enabled.
Why is this Pull Request needed?
Without this fix, m3u8 is reload after target-duration and cause the low latency stream buffer to be stalled, when the total parts loaded in the buffer is lower than target-duration (which is a property for normal-latency mode).
Are there any points in the code the reviewer needs to double check?
I think this can be optimized more (increase the interval to partTarget + hint.duration) to reduce m3u8 reload if PRELOAD HINT is fully supported as in https://github.com/video-dev/hls.js/issues/3988. However, it's risky as the PRELOAD HINT has to carefully check for whether the hinted part is fully available or not.
Resolves issues:
This manifest will cause hlsjs to be stuck as the very first m3u8 reload is set to 4 (TARGETDURATION) but the buffer loaded on 3 parts (PART-HOLD-BACK = 3.84):
#EXTM3U
#EXT-X-TARGETDURATION:4
#EXT-X-VERSION:6
#EXT-X-MEDIA-SEQUENCE:140
#EXT-X-SERVER-CONTROL:PART-HOLD-BACK=3.84
#EXT-X-PART-INF:PART-TARGET=1.28
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-PROGRAM-DATE-TIME:2025-01-26T14:23:52.970Z
#EXT-X-MAP:URI="segment_init.mp4"
#EXTINF:3.84,
segment_140.m4s
#EXTINF:3.84,
segment_141.m4s
#EXTINF:3.84,
segment_142.m4s
#EXTINF:3.84,
segment_143.m4s
#EXT-X-PART:DURATION=1.28,URI="segment_144.m4s.1",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.28,URI="segment_144.m4s.2",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.28,URI="segment_144.m4s.3",INDEPENDENT=YES
#EXTINF:3.84,
segment_144.m4s
#EXT-X-PART:DURATION=1.28,URI="segment_145.m4s.1",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.28,URI="segment_145.m4s.2",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.28,URI="segment_145.m4s.3",INDEPENDENT=YES
#EXTINF:3.84,
segment_145.m4s
#EXT-X-PART:DURATION=1.28,URI="segment_146.m4s.1",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.28,URI="segment_146.m4s.2",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.28,URI="segment_146.m4s.3",INDEPENDENT=YES
#EXTINF:3.84,
segment_146.m4s
#EXT-X-PART:DURATION=1.28,URI="segment_147.m4s.1",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.28,URI="segment_147.m4s.2",INDEPENDENT=YES
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="segment_147.m4s.3"
#EXT-X-RENDITION-REPORT:URI="../audio_hd/playlist.m3u8",LAST-MSN=147,LAST-PART=3
Checklist
- [ x ] changes have been done against master branch, and PR does not conflict
- [ x ] new unit / functional tests have been added (whenever applicable)
- [ x ] API or design changes are documented in API.md
Low-latency HLS playlist are expected to implement blocking reload. Without it, clients shouldn't even attempt to load parts or play from part holdback.
See HLS spec Appendix B.1: Low-Latency Server Configuration Profile
clients can and SHOULD fall back to regular-latency playback if they discover that the server does not meet the requirements of this configuration profile.
Is there a reason why you are not using blocking reload on a playlist with parts (#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES)? If you do not, you should not expect clients to use parts. The lowLatencyMode configuration option is there to be explicitly disable, not to force part loading when it should not be performed.
Low-latency HLS playlist are expected to implement blocking reload. Without it, clients shouldn't even attempt to load parts or play from part holdback.
See HLS spec Appendix B.1: Low-Latency Server Configuration Profile
clients can and SHOULD fall back to regular-latency playback if they discover that the server does not meet the requirements of this configuration profile.
Is there a reason why you are not using blocking reload on a playlist with parts (#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES)? If you do not, you should not expect clients to use parts. The
lowLatencyModeconfiguration option is there to be explicitly disable, not to force part loading when it should not be performed.
Thank you for the explanation. Due to the complexity on the server side so we haven't implemented the feature yet but yes, agree that we should have that feature enabled for low latency.
Btw, if so, is it true that hls.js should treat my m3u8 as regular-latency mode and should not load these parts? Let's consider it as a malformed manifest.
Btw, if so, is it true that hls.js should treat my m3u8 as regular-latency mode and should not load these parts? Let's consider it as a malformed manifest.
It should. To do so, in shouldLoadParts hls.js should verify both details.partList and details.canBlockReload before returning true. details.canBlockReload must also be considered in get targetLatency so that we use standard hold back rather than the part hold back.
Low-latency live streams are only supported using blocking reload requests with delivery directives. HLS clients are not meant to poll Low-latency live playlists based on a part target interval. This behavior this PR was made for is not valid HLS.