hls.js supports fallback to backup-renditions in older versions, but it generally seems to fail on playlists with GROUP-IDs, supporting alternate audio.
More info on Primary/Backup-Playlists:
https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StreamingMediaGuide/UsingHTTPLiveStreaming/UsingHTTPLiveStreaming.html#//apple_ref/doc/uid/TP40008332-CH102-SW22
More info on Error-Handling for HTTP-Live-Streaming:
https://developer.apple.com/videos/play/wwdc2017/514/
there is a final "error while loading level playlist" instead of falling back to the backup source.
[log] > loadSource:https://apiproxy.akamaized.net/hlsjs/av/master_prim_faila.m3u8
logger.js:37 [log] > trigger BUFFER_RESET
logger.js:37 [log] > set autoLevelCapping:-1
logger.js:37 [log] > attachMedia
logger.js:37 [log] > media source opened
logger.js:37 [log] > manifest loaded,1 level(s) found, first bitrate:1288815
logger.js:37 [log] > startLoad(-1)
logger.js:37 [log] > switching to level 0
logger.js:37 [log] > loading playlist for level 0
logger.js:37 [log] > main stream:STOPPED->IDLE
logger.js:37 [log] > audio tracks updated
logger.js:37 [log] > subtitle tracks updated
xhr-loader.js:80 GET https://apiproxy.akamaized.net/hlsjs/av/av-1400-p/prog_index.m3u8 404 (Not Found)
loadInternal @ xhr-loader.js:80
load @ xhr-loader.js:39
load @ playlist-loader.js:217
onLevelLoading @ playlist-loader.js:170
onEventGeneric @ event-handler.js:65
onEvent @ event-handler.js:53
EventEmitter.emit @ events.js:84
trigger @ hls.js:88
setLevelInternal @ level-controller.js:177
set @ level-controller.js:151
set @ level-controller.js:372
set @ hls.js:245
startLoad @ stream-controller.js:88
(anonymous) @ hls.js:178
startLoad @ hls.js:178
onManifestParsed @ stream-controller.js:898
onEventGeneric @ event-handler.js:65
onEvent @ event-handler.js:53
EventEmitter.emit @ events.js:96
trigger @ hls.js:88
onManifestLoaded @ level-controller.js:120
onEventGeneric @ event-handler.js:65
onEvent @ event-handler.js:53
EventEmitter.emit @ events.js:96
trigger @ hls.js:88
loadsuccess @ playlist-loader.js:530
readystatechange @ xhr-loader.js:117
XMLHttpRequest.send (async)
loadInternal @ xhr-loader.js:80
load @ xhr-loader.js:39
load @ playlist-loader.js:217
onManifestLoading @ playlist-loader.js:166
onEventGeneric @ event-handler.js:65
onEvent @ event-handler.js:53
EventEmitter.emit @ events.js:96
trigger @ hls.js:88
loadSource @ hls.js:173
loadStream @ ?src=https%3A%2F%2Fapiproxy.akamaized.net%2Fhlsjs%2Fav%2Fmaster_prim_faila.m3u8&enableStreaming=true&autoRecoverError=true&enableWorker=true&dumpfMP4=false&levelCapping=-1&defaultAudioCodec=undefined:285
(anonymous) @ ?src=https%3A%2F%2Fapiproxy.akamaized.net%2Fhlsjs%2Fav%2Fmaster_prim_faila.m3u8&enableStreaming=true&autoRecoverError=true&enableWorker=true&dumpfMP4=false&levelCapping=-1&defaultAudioCodec=undefined:258
logger.js:37 [error] > 404 while loading https://apiproxy.akamaized.net/hlsjs/av/av-1400-p/prog_index.m3u8
(anonymous) @ logger.js:37
readystatechange @ xhr-loader.js:121
XMLHttpRequest.send (async)
loadInternal @ xhr-loader.js:80
load @ xhr-loader.js:39
load @ playlist-loader.js:217
onLevelLoading @ playlist-loader.js:170
onEventGeneric @ event-handler.js:65
onEvent @ event-handler.js:53
EventEmitter.emit @ events.js:84
trigger @ hls.js:88
setLevelInternal @ level-controller.js:177
set @ level-controller.js:151
set @ level-controller.js:372
set @ hls.js:245
startLoad @ stream-controller.js:88
(anonymous) @ hls.js:178
startLoad @ hls.js:178
onManifestParsed @ stream-controller.js:898
onEventGeneric @ event-handler.js:65
onEvent @ event-handler.js:53
EventEmitter.emit @ events.js:96
trigger @ hls.js:88
onManifestLoaded @ level-controller.js:120
onEventGeneric @ event-handler.js:65
onEvent @ event-handler.js:53
EventEmitter.emit @ events.js:96
trigger @ hls.js:88
loadsuccess @ playlist-loader.js:530
readystatechange @ xhr-loader.js:117
XMLHttpRequest.send (async)
loadInternal @ xhr-loader.js:80
load @ xhr-loader.js:39
load @ playlist-loader.js:217
onManifestLoading @ playlist-loader.js:166
onEventGeneric @ event-handler.js:65
onEvent @ event-handler.js:53
EventEmitter.emit @ events.js:96
trigger @ hls.js:88
loadSource @ hls.js:173
loadStream @ ?src=https%3A%2F%2Fapiproxy.akamaized.net%2Fhlsjs%2Fav%2Fmaster_prim_faila.m3u8&enableStreaming=true&autoRecoverError=true&enableWorker=true&dumpfMP4=false&levelCapping=-1&defaultAudioCodec=undefined:285
(anonymous) @ ?src=https%3A%2F%2Fapiproxy.akamaized.net%2Fhlsjs%2Fav%2Fmaster_prim_faila.m3u8&enableStreaming=true&autoRecoverError=true&enableWorker=true&dumpfMP4=false&levelCapping=-1&defaultAudioCodec=undefined:258
logger.js:37 [warn] > level controller,levelLoadError for level 0: switching to redundant stream id 1
(anonymous) @ logger.js:37
onError @ level-controller.js:273
onEventGeneric @ event-handler.js:65
onEvent @ event-handler.js:53
EventEmitter.emit @ events.js:96
trigger @ hls.js:88
loaderror @ playlist-loader.js:560
readystatechange @ xhr-loader.js:122
XMLHttpRequest.send (async)
loadInternal @ xhr-loader.js:80
load @ xhr-loader.js:39
load @ playlist-loader.js:217
onLevelLoading @ playlist-loader.js:170
onEventGeneric @ event-handler.js:65
onEvent @ event-handler.js:53
EventEmitter.emit @ events.js:84
trigger @ hls.js:88
setLevelInternal @ level-controller.js:177
set @ level-controller.js:151
set @ level-controller.js:372
set @ hls.js:245
startLoad @ stream-controller.js:88
(anonymous) @ hls.js:178
startLoad @ hls.js:178
onManifestParsed @ stream-controller.js:898
onEventGeneric @ event-handler.js:65
onEvent @ event-handler.js:53
EventEmitter.emit @ events.js:96
trigger @ hls.js:88
onManifestLoaded @ level-controller.js:120
onEventGeneric @ event-handler.js:65
onEvent @ event-handler.js:53
EventEmitter.emit @ events.js:96
trigger @ hls.js:88
loadsuccess @ playlist-loader.js:530
readystatechange @ xhr-loader.js:117
XMLHttpRequest.send (async)
loadInternal @ xhr-loader.js:80
load @ xhr-loader.js:39
load @ playlist-loader.js:217
onManifestLoading @ playlist-loader.js:166
onEventGeneric @ event-handler.js:65
onEvent @ event-handler.js:53
EventEmitter.emit @ events.js:96
trigger @ hls.js:88
loadSource @ hls.js:173
loadStream @ ?src=https%3A%2F%2Fapiproxy.akamaized.net%2Fhlsjs%2Fav%2Fmaster_prim_faila.m3u8&enableStreaming=true&autoRecoverError=true&enableWorker=true&dumpfMP4=false&levelCapping=-1&defaultAudioCodec=undefined:285
(anonymous) @ ?src=https%3A%2F%2Fapiproxy.akamaized.net%2Fhlsjs%2Fav%2Fmaster_prim_faila.m3u8&enableStreaming=true&autoRecoverError=true&enableWorker=true&dumpfMP4=false&levelCapping=-1&defaultAudioCodec=undefined:258
?src=https%3A%2F%2Fapiproxy.akamaized.net%2Fhlsjs%2Fav%2Fmaster_prim_faila.m3u8&enableStreaming=true&autoRecoverError=true&enableWorker=true&dumpfMP4=false&levelCapping=-1&defaultAudioCodec=undefined:528 {type: "networkError", details: "levelLoadError", fatal: false, url: undefined, loader: XhrLoader,聽鈥
This is pretty curious - if i click on the demo link (#1 in steps to reproduce) the playback starts. But if you reload the demo-page it's getting broken.
In version 0.8.2 or below this seems to work fine.
Thanks @netTrekfd for opening this ticket!
one note:
hls.js Support for Primary/Backup Failover for HLS-Streams with Alternate Audio
e.g. https://apiproxy.akamaized.net/hlsjs/multichannelaudio/master_prim_fail_v1a.m3u8
has never worked (at least tested with hls.js 0.62-0.87).
I gave it a try and this commit broke something between 0.8.2 and 0.8.3 (stream controller is stuck in IDLE if first level request fails ...)
but then while rechecking against 0.8.7 I found out that a second thing has been broken : the logic dealing with switching to redundant level in case level request fails has been removed (most probably by https://github.com/video-dev/hls.js/pull/1346)
ping @NicolasSiver
I'm going to look into this. What exactly we had in 0.8.2 which would drive a switch to backup stream for a level manifest.
With latest changes it works:

I will push PR soon.
Thanks @NicolasSiver for providing the fix. I can confirm that the first of my sample streams now is playable.
But the error persists for my second sample (multiaudio playlist) where both the primary video & primary audio manifests are broken:
https://apiproxy.akamaized.net/hlsjs/multichannelaudio/master_prim_fail_v1a.m3u8
Can you please check and reopen?
Thanks!
@NicolasSiver @mangui Could you please recheck this issue with my teststream (see comment above). I think the switching logic is still broken. Or shall i create a new ticket for it?
Thanks!
@netTrekfd Hey! I tested and indeed the 404 error doesn't recover well. Would need to look further into this. Feel free to contact me directly.
@netTrekfd this might fix this issue in a simple way ^ :) check it out.
Re-opening this as it is not fixed on master yet, see PR https://github.com/video-dev/hls.js/pull/1630 which fixes this partly (but not merged yet).
Here is an updated description of the issue which is partly solved by above PR
Status:
Expected behavior:
Sample-Playlist:
https://apiproxy.akamaized.net/hlsjs/multichannelaudio/master_prim_fail_v1a.m3u8
https://apiproxy.akamaized.net/hlsjs/zdf/check_primfail4.m3u8
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.