FetchLoader has missing implementation of error retry logic presented in XhrLoader
What version of Hls.js are you using?
1.6.3
What browser (including version) are you using?
Any
What OS (including version) are you using?
Any
Test stream
No response
Configuration
{
}
Additional player setup steps
Use hls.js with error network retries enabled, something like this:
const MANIFEST_LOAD_RETRY_POLICY: Partial<RetryConfig> = {
maxNumRetry: 10,
retryDelayMs: 250,
backoff: "exponential",
shouldRetry: (retryConfig, retryCount, isTimeout, loaderResponse) => {
if (!retryConfig) {
return false;
}
const retryForHttpStatus = (httpStatus: number | undefined) =>
// Do not retry on status 4xx, status 0 (CORS error), or undefined (decrypt/gap/parse error)
(httpStatus === 0 && navigator.onLine === false) ||
(!!httpStatus &&
(httpStatus < 400 || httpStatus > 499 || httpStatus === 401));
const httpStatus = loaderResponse?.code;
const retry =
retryCount < retryConfig.maxNumRetry &&
(retryForHttpStatus(httpStatus) || !!isTimeout);
return retry;
},
};
const mergedConfig = {
...Hls.DefaultConfig,
loader: FetchLoader,
};
if (mergedConfig.manifestLoadPolicy.default.errorRetry) {
Object.assign(
mergedConfig.manifestLoadPolicy.default.errorRetry,
MANIFEST_LOAD_RETRY_POLICY
);
}
Checklist
- [x] The issue observed is not already reported by searching on Github under https://github.com/video-dev/hls.js/issues
- [x] The issue occurs in the stable client (latest release) on https://hlsjs.video-dev.org/demo and not just on my page
- [x] The issue occurs in the latest client (main branch) on https://hlsjs-dev.video-dev.org/demo and not just on my page
- [x] The stream has correct Access-Control-Allow-Origin headers (CORS)
- [x] There are no network errors such as 404s in the browser console when trying to play the stream
Steps to reproduce
- Use hls.js to play stream;
- Receive transient server error during main manifest download;
Expected behaviour
Download of manifest is retried (including 401 error due to custom retry config provided).
What actually happened?
Download of manifest is not retried, receiving fatal error and the following error handler does not trigger re-download:
case Hls.ErrorTypes.NETWORK_ERROR:
hls.startLoad();
break;
No retry implemented in FetchLoader: https://github.com/video-dev/hls.js/blame/2fb519b6456299b59c9c33f760accece03d2e2f6/src/utils/fetch-loader.ts#L139-L143 While XhrLoader has proper retry logic: https://github.com/video-dev/hls.js/blame/2fb519b6456299b59c9c33f760accece03d2e2f6/src/utils/xhr-loader.ts#L237-L256
Console output
[log] > Debug logs enabled for "Hls instance" in hls.js version 1.6.3
HLSPlayer.tsx:230 effective hls.js config: {autoStartLoad: true, startPosition: -1, defaultAudioCodec: undefined, debug: true, capLevelOnFPSDrop: false, …}
HLSPlayer.tsx:426 [log] > stopLoad
HLSPlayer.tsx:426 [log] > loadSource:https://server/master.m3u8?tech=hls
HLSPlayer.tsx:426 [log] > [stream-controller]: Trigger BUFFER_RESET
HLSPlayer.tsx:427 [log] > attachMedia
HLSPlayer.tsx:427 [log] > [buffer-controller]: created media source: MediaSource
HLSPlayer.tsx:441 [log] > startLoad(-1)
HLSPlayer.tsx:441 [log] > [subtitle-stream-controller]: STOPPED->IDLE
hls.mjs:18235 [log] > [buffer-controller]: Media source opened
hls.mjs:19292 [log] > [buffer-controller]: checkPendingTracks (pending: 0 codec events expected: 0) {}
HLSPlayer.tsx:426 GET https://server/master.m3u8?tech=hls 401 (Unauthorized)
HLSPlayer.tsx:426 [warn] > [playlist-loader]: A network error (status 401) occurred while loading manifest
hls.mjs:9860 [log] > [stream-controller]: STOPPED->ERROR
hls.mjs:9860 [log] > [audio-stream-controller]: STOPPED->ERROR
hls.mjs:34774 [log] > stopLoad
hls.mjs:9860 [log] > [stream-controller]: ERROR->STOPPED
hls.mjs:9860 [log] > [audio-stream-controller]: ERROR->STOPPED
hls.mjs:9860 [log] > [subtitle-stream-controller]: IDLE->STOPPED
HLSPlayer.tsx:304 HLS.js error: fatal=true networkError, manifestLoadError
HLSPlayer.tsx:312 [log] > startLoad(-1)
HLSPlayer.tsx:312 [log] > [subtitle-stream-controller]: STOPPED->IDLE
Chrome media internals output
Manifest load errors are fatal and therefore not retried. I'm not sure this is an issue with the FetchLoader specifically when the example is manifest load failure.
No retry implemented in FetchLoader: https://github.com/video-dev/hls.js/blame/2fb519b6456299b59c9c33f760accece03d2e2f6/src/utils/fetch-loader.ts#L139-L143 While XhrLoader has proper retry logic: https://github.com/video-dev/hls.js/blame/2fb519b6456299b59c9c33f760accece03d2e2f6/src/utils/xhr-loader.ts#L237-L256
Would you like to contribute a fix for the issue?
Would you like to contribute a fix for the issue?
I can try to do so, but can't promise I'll complete it quickly, because it looks like control flow within FetchLoader is somewhat complex and I'll need to dive deep to find a way to introduce retries and not change implementation too much.
In case you already see how it should be fixed I don't mind you fix it :)
Priority is lower for me. It doesn't impact the default loader/setup. It isn't a regression. And, it does not impact fragment retry handled by stream controllers.