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

fix: Keep media update timeout alive so live playlists can recover #1176

Merged
merged 8 commits into from
Aug 17, 2021

Conversation

brandonocasey
Copy link
Contributor

@brandonocasey brandonocasey commented Jul 29, 2021

Description

Right now for live hls streams we can be stuck buffering even though we should have recovered because we don't attempt to retry requests. You can reproduce this:

  1. Select Unified Streaming Live HLS
  2. Play
  3. Set network to offline in dev tools
  4. Wait for the player to stall
  5. Set network back to normal in dev tools
  6. Player will never recover

This happens because we exclude and pause the current playlist loader when it fails a request. Then we switch to same playlist again and since it is the same playlist we don't try to request it again. So now we have no mediaUpdateTimeout and we did not request the playlist again.

The fix

  1. We need a way to make sure that we start a mediaUpdateTimeout in media
  2. We need mediaUpdateTimeouts to create media update timeouts
  3. We do not need to always return true in shouldSwitchToMedia for live playlists if the playlist is the same. This gave us state we have now as we were relying on abr to refresh live playlists in some scenarios.

@codecov
Copy link

codecov bot commented Jul 29, 2021

Codecov Report

Merging #1176 (5f2c279) into main (e8230a9) will increase coverage by 0.03%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1176      +/-   ##
==========================================
+ Coverage   86.51%   86.54%   +0.03%     
==========================================
  Files          39       39              
  Lines        9602     9619      +17     
  Branches     2219     2222       +3     
==========================================
+ Hits         8307     8325      +18     
+ Misses       1295     1294       -1     
Impacted Files Coverage Δ
src/master-playlist-controller.js 94.62% <100.00%> (+0.02%) ⬆️
src/playlist-loader.js 94.29% <100.00%> (+0.56%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e8230a9...5f2c279. Read the comment docs.

const media = this.media();

if (shouldDelay) {
const delay = media ? ((media.partTargetDuration || media.targetDuration) / 2) * 1000 : 5 * 1000;

this.mediaUpdateTimeout = window.setTimeout(() => this.load(), delay);
this.mediaUpdateTimeout = window.setTimeout(() => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo this should be called something else, but I think we should save it for the playlist-loader base class refactor as dash-playlist-loader does the same thing.

gkatsev
gkatsev previously approved these changes Jul 30, 2021
Copy link
Member

@gkatsev gkatsev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't tested yet but changes make sense to me.

@@ -67,7 +67,7 @@ const shouldSwitchToMedia = function({
// This is because in LIVE, the player plays 3 segments from the end of the
// playlist, and if `BUFFER_LOW_WATER_LINE` is greater than the duration availble
// in those segments, a viewer will never experience a rendition upswitch.
if (!currentPlaylist || !currentPlaylist.endList) {
if (!currentPlaylist) {
log(`${sharedLogLine} as current playlist ` + (!currentPlaylist ? 'is not set' : 'is live'));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per the comment above, will this mean that we should have a way of ignoring the low water for live in the rest of this function?

And we may need to update this line and the comment above

@@ -619,6 +613,8 @@ export default class PlaylistLoader extends EventTarget {
return;
}

this.updateMediaUpdateTimeout_(refreshDelay(playlist, true));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be worth a comment above here saying why we update the timeout even if it's switching to the active playlist

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

Comment on lines 2036 to 2065
endList = false;
currentTime = 100;
currentPlaylistBandwidth = 1000;
nextPlaylistBandwidth = 1001;
buffered = [];
this.masterPlaylistController.mainSegmentLoader_.trigger('bandwidthupdate');
assert.equal(
mediaChanges.length,
1,
'changes live media when no buffer and higher bandwidth playlist'
);
buffered = [[0, 100], [100, 109]];
this.masterPlaylistController.mainSegmentLoader_.trigger('bandwidthupdate');
assert.equal(
mediaChanges.length,
2,
'changes live media when insufficient forward buffer and higher ' +
'bandwidth playlist'
);
buffered = [[0, 100], [100, 130]];
this.masterPlaylistController.mainSegmentLoader_.trigger('bandwidthupdate');
assert.equal(
mediaChanges.length,
3,
'changes live media when sufficient forward buffer and higher ' +
'bandwidth playlist'
);

mediaChanges.length = 0;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to remove these tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These only tested that live content always switches as far as I could tell. We might have to add one more back in depending on changes that I have to make in shouldSwitchToMedia.

@@ -351,7 +356,7 @@ export class MasterPlaylistController extends videojs.EventTarget {
checkABR_() {
const nextPlaylist = this.selectPlaylist();

if (this.shouldSwitchToMedia_(nextPlaylist)) {
if (nextPlaylist && this.shouldSwitchToMedia_(nextPlaylist)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor fix here. I saw that we throw an error if nextPlaylist is undefined.

Copy link
Member

@gkatsev gkatsev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can confirm that this fixes the issue of going offline and coming back!

src/playlist-loader.js Show resolved Hide resolved
@brandonocasey brandonocasey merged commit 8b3533c into main Aug 17, 2021
@brandonocasey brandonocasey deleted the fix/live-media-update-timeout branch August 17, 2021 19:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants