-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Redundant streams fallback behavior for alternate renditions with multiple media groups #1630
Conversation
May fix parts of #1438 |
src/loader/playlist-loader.js
Outdated
@@ -152,24 +152,26 @@ class PlaylistLoader extends EventHandler { | |||
} | |||
|
|||
onManifestLoading (data) { | |||
this.load(data.url, { type: ContextType.MANIFEST }); | |||
this.load(data.url, { type: ContextType.MANIFES, level: null, id: null }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a little type error, should be:
this.load(data.url, { type: ContextType.MANIFEST, level: null, id: null });
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
which is why stuff currently fails 👍
get audioTrack () { | ||
return this.trackId; | ||
} | ||
|
||
/** select an audio track, based on its index in audio track lists**/ | ||
set audioTrack (audioTrackId) { | ||
if (this.trackId !== audioTrackId || this.tracks[audioTrackId].details === undefined) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mangui how did the condition to run the set internal make sense: this.tracks[audioTrackId].details === undefined
?
wouldn't you still want to switch even if the metadata is not loaded yet?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
condition is :
call set internal
if new track id OR if same track id but details not available yet (in that case it will force a reload of the details)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
of course, makes sense :) thanks for the explanation. i have added the check for the details
prop in this branch now as well to make sure we are allowing to switch track in this case as well.
9ecd32e
to
266d64c
Compare
266d64c
to
556cd06
Compare
@mangui @johnBartos @tjenkinson Hey guys, do you think you could check this out? just to make sure i didn't break something badly :) Will also add unit tests for this behavior hopefully as soon as I get to it! |
… details lack (recovers previous logic after refactor)
src/controller/abr-controller.js
Outdated
@@ -31,7 +31,12 @@ class AbrController extends EventHandler { | |||
} | |||
|
|||
onFragLoading (data) { | |||
let frag = data.frag; | |||
const hls = this.hls; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hls
and config
objects were only initialized if useful before.
now you will have extra processing everytime a subtitle or audio frag is loading.
you could argue that this might look like micro-optimization, but still ;-)
src/controller/abr-controller.js
Outdated
isLive = hls.levels[level].details.live, | ||
config = hls.config, | ||
ewmaFast, ewmaSlow; | ||
let level = data.frag.level; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let level = frag.level
is shorter
src/controller/abr-controller.js
Outdated
@@ -55,8 +57,9 @@ class AbrController extends EventHandler { | |||
} | |||
this._bwEstimator = new EwmaBandWidthEstimator(hls, ewmaSlow, ewmaFast, config.abrEwmaDefaultEstimate); | |||
} | |||
this.fragCurrent = frag; | |||
this._bwEstimator = new EwmaBandWidthEstimator(hls, ewmaSlow, ewmaFast, config.abrEwmaDefaultEstimate); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like bwEstimator is created twice now ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
true. was debugging this stuff and left some mess around :/
src/controller/abr-controller.js
Outdated
} | ||
this.fragCurrent = frag; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should not update this.fragCurrent
if frag
is not from main
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i was actually wondering about that. i think there was a bug however here, we were sometimes hitting an undefined fragCurrent
..? but maybe it's fixed now, i was trying to debug this part and something was fishy.
…age of current track and using group ID currently running
…her controllers to ensure they are on the correct group ID
Hi @tchakabam, And if yes, does hls.js ensure that all active medias are from the same group? |
Hi @axten Yes. That's exactly the idea. In this branch this should work as expected now. |
ok great! this is exactly what we need! cannot await this to land :) |
@axten That's what I had been told as well 👍 Very well, then this will need some clean-up and polishing, but the functionality is now there. We were actually missing the information inside our Quality-Level data-model where we are handling redundant streams by nesting various URLs for the same quality, but as a result were compressing away the various audio-group IDs for the respective redundants streams. This information is now being patched onto the data-model along with the redundant URLs. Furthermore, the audio-track switched event is being handled now by the level-controller (which is triggered also when we switch for failure fallback) in order to make sure that the current level played is actually for the group ID of the latest selected audio-track. If that is not the case, we will correct that setting internally and re-load the video levels accordingly. In a way like a mirror, the analogous logic is implemented for audio-tracks. As a quality level is switched (wether it be for any reason, manually or by recovery/fallback mechanisms) we check which actual stream is being played of the redundant options, and which audio-group-id that corresponds. If that doesn't match the audio-group-ID of the currently selected audio-track, we switch it accordingly, while trying to preserve the actual name/language setting which indicates the logical "role" of this audio track (to avoid switching say from original audio to audio for visibility handicap etc). Further things to do now would be:
=> Then we should be able to merge this into our master branch. You could anyhow already use this branch here for your testing to validate we got it all right, and in principle also for your prod player already, if it works for you (and after we removed a few hard-coded log lines maybe :)). |
} | ||
const newTrack = this.tracks[i]; | ||
if (newTrack.name === name && | ||
newTrack.language === language) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why check for both name
and language
here but only name
on _selectInitialAudioTrack? From what I see in the spec only name
is required to both exist and be consistent across groups. Any sane manifest will have matching and unique names and languages, but it may be worth being consistent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Name should be sufficient, you're right.
Build pipeline succeeded (not sure why it's greyed out however): https://travis-ci.org/video-dev/hls.js/builds/389764334 |
Description of the Changes
Until now, we are not supporting a typical live broadcast use-case: using backup streams for all alternate audio and subtitle rendition options, grouping these into respective group-IDs. For example group-ID A groups all the primary renditions and video-levels, B all the back ones. In this case, group-IDs of selected audio and subtitle renditions need to be matched to the group-ID of the running level and vice versa. So if we fallback on a level, we have to re-select the rendition so to match the group ID, and if we fallback on audio we may have to switch to the matching redundant level. That is because the grouped renditions/levels actually run on sync'ed encoders, while if the groups don't match, there can easily be A/V-sync issues. In fact, the clocks of the redundants streams across group IDs are not actually even specified to have anything like matching clocks or so, they could operate in completely different timeline.
=> This PR will fix the above and allow proper fallback behavior across all directions (video-levels <-> audio-and-subs-renditions)
CheckLists