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: playback watcher should fix seeking into a gap. #1192

Merged
merged 13 commits into from
Sep 3, 2021

Conversation

brandonocasey
Copy link
Contributor

Description

playback watcher should seek us out of a gap that was seeked into.

@codecov
Copy link

codecov bot commented Aug 31, 2021

Codecov Report

Merging #1192 (375c4ff) into main (9aeb77b) will increase coverage by 0.03%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1192      +/-   ##
==========================================
+ Coverage   86.55%   86.59%   +0.03%     
==========================================
  Files          39       39              
  Lines        9619     9645      +26     
  Branches     2225     2233       +8     
==========================================
+ Hits         8326     8352      +26     
  Misses       1293     1293              
Impacted Files Coverage Δ
src/playback-watcher.js 99.19% <100.00%> (+0.03%) ⬆️
src/playlist-loader.js 94.31% <100.00%> (+0.01%) ⬆️
src/ranges.js 99.34% <100.00%> (+0.06%) ⬆️

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 9aeb77b...375c4ff. Read the comment docs.

@@ -253,7 +267,7 @@ export default class PlaybackWatcher {
* @private
*/
checkCurrentTime_() {
if (this.tech_.seeking() && this.fixesBadSeeks_()) {
if (this.fixesBadSeeks_()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixesBadSeeks_ already returns false if seeking is false on tech so checking seeking is redundant.

@@ -426,7 +445,7 @@ export default class PlaybackWatcher {
const seekable = this.seekable();
const currentTime = this.tech_.currentTime();

if (this.tech_.seeking() && this.fixesBadSeeks_()) {
if (this.fixesBadSeeks_()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixesBadSeeks_ already returns false if seeking is false on tech so checking seeking is redundant.

@@ -340,7 +340,8 @@ export const updateMaster = (master, newMedia, unchangedCheck = isPlaylistUnchan
* The time in ms to wait before refreshing the live playlist
*/
export const refreshDelay = (media, update) => {
const lastSegment = media.segments[media.segments.length - 1];
const segments = media.segments || [];
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixes an issue I was seeing in our multi period source where sometimes media does not have segments. I can make this a different pull request, but it was easy enough.

@@ -445,3 +445,32 @@ export const lastBufferedEnd = function(a) {

return a.end(a.length - 1);
};

export const timeAheadOf = function(range, startTime) {
let time = 0;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This function allows us to keep the previous logic where we made sure that two segment appends had happened while the player is seeking. The problem with the previous logic is that it did not consider all of the buffer after currentTime. This code adds up all of the buffer after currentTime gaps and all.

targetDuration: this.media().targetDuration,
currentTime
})
) {
seekTo = buffered.start(0) + Ranges.SAFE_TIME_DELTA;
this.logger_(`Buffered region starts (${buffered.start(0)}) ` +
const nextRange = Ranges.findNextRange(buffered, currentTime);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Example values for why we need this:

buffered = [[0, 10], [21, 40]]
currentTime = 20

Previously we would just take buffered.start(0) which is in this case is before currentTime. Now we find the TimeRange that is after currentTime and use that.

}
export const closeToBufferedContent = ({ buffered, audioBuffered, videoBuffered, targetDuration, currentTime }) => {
const twoSegmentDurations = (targetDuration - Ranges.TIME_FUDGE_FACTOR) * 2;
const bufferedToCheck = [audioBuffered, videoBuffered];
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wasn't sure of a better way to fix this. Sometimes we will have one or the other and sometimes we will have both. We need to make sure that both buffers have two segment durations appended ahead of current time before we do anything. We do this because fixesBadSeeks on a setTimeout whenever tech.seeking() is true. Ideally we would go back to what I had using events and never using a timer, but that would require too much testing.

if (currentTime > buffered.start(0)) {
// default to using buffered, but if we don't have one
// use video or audio buffered
buffered = buffered && buffered.length ? buffered : null;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I saw a case were we had no bufferIntersection but we did have a video/audio buffer. Seeking to the start of the next videoBuffer fixed it for us.

return false;
}

// Since target duration generally represents the max (or close to max) duration of a
// segment, if the buffer is within a segment of the current time, the gap probably
// won't be closed, and current time should be considered close to buffered content.
return buffered.start(0) - currentTime < targetDuration;
return nextRange.start(0) - currentTime < (targetDuration + Ranges.TIME_FUDGE_FACTOR);
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 time fudge factor here because segment durations are never exact.

@@ -1006,6 +1006,12 @@ QUnit.test('jumps to buffered content if seeking just before', function(assert)
currentTime: () => currentTime,
buffered: () => buffered
};

Object.assign(playbackWatcher.masterPlaylistController_.sourceUpdater_, {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

had to update this test to pass videoBuffered, other than that all tests continue to work.

src/ranges.js Outdated
export const timeAheadOf = function(range, startTime) {
let time = 0;

if (!range || !range.length || !range.end) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is !range.end necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

not sure we do it in other functions in this file.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it was a mistake? I think end is a method.

Co-authored-by: Gary Katsevman <[email protected]>
src/ranges.js Outdated
export const timeAheadOf = function(range, startTime) {
let time = 0;

if (!range || !range.length || !range.end) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it was a mistake? I think end is a method.

@brandonocasey brandonocasey merged commit 61b8eef into main Sep 3, 2021
@brandonocasey brandonocasey deleted the fix/handle-seek-to-gap branch September 3, 2021 17:13
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