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: audio segment on incorrect timeline #1530

Merged
merged 7 commits into from
Aug 12, 2024

Conversation

wseymour15
Copy link
Contributor

@wseymour15 wseymour15 commented Aug 6, 2024

Description

Currently there is an edge case in DASH where certain points of audio segments and video segments do not always exist on the same timeline.

Example: We seek to 100 seconds into the video. There is an audio segment that is from 98-100.25 seconds, and the video segment is from 100-109.95. The audio segment is on a timeline from 90-99.99, and the video segment is on a timeline from 110-119.99. We fall into a loop in this scenario because VHS catches that we have bad timelines, but we do not do anything to fix it in this scenario.

This change allows us to check for this specific scenario. When we attempt to load an audio segment that is on a prior timeline to the video segment, we will now force the player forward to just past the faulty audio segment. This ensures that the audio and video segments will now be on the same timeline.

Specific Changes proposed

  • Moves the fixBadTimeline logic outside of the hasEnoughInfoToLoad_ and hasEnoughInfoToAppend_ functions so we do not have unexpected actions on a function that should just return a boolean.
  • Create an event for when the audio segment is on a prior timeline to what the main video segment is on.
  • Update the pending audio timeline change, and set the currentTime to just after the end of the faulty audio segment.

Requirements Checklist

  • Feature implemented / Bug fixed
  • If necessary, more likely in a feature request than a bug fix
  • Reviewed by Two Core Contributors

Copy link

codecov bot commented Aug 6, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 86.36%. Comparing base (d23539a) to head (efe1d0d).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1530      +/-   ##
==========================================
+ Coverage   86.33%   86.36%   +0.03%     
==========================================
  Files          43       43              
  Lines       11118    11144      +26     
  Branches     2540     2545       +5     
==========================================
+ Hits         9599     9625      +26     
  Misses       1519     1519              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@@ -413,6 +413,11 @@ export const shouldFixBadTimelineChanges = (timelineChangeController) => {
const pendingAudioTimelineChange = timelineChangeController.pendingTimelineChange({ type: 'audio' });
const pendingMainTimelineChange = timelineChangeController.pendingTimelineChange({ type: 'main' });
const hasPendingTimelineChanges = pendingAudioTimelineChange && pendingMainTimelineChange;

if (hasPendingTimelineChanges && pendingAudioTimelineChange.to < pendingMainTimelineChange.to) {
timelineChangeController.trigger('audioTimelineBehind');
Copy link
Contributor

Choose a reason for hiding this comment

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

Should it be inside should fix bad timeline changes?
this looks like a side effect, and should be moved outside

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 agree that this can be moved elsewhere.. but I think there are a few different places it could be placed.

Do you think it would make sense to just check after an audio timeline change?

Copy link
Contributor

Choose a reason for hiding this comment

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

probably yes

// forwards playback to a point where these two segment types are back on the same
// timeline. This time will be just after the end of the audio segment that is on
// a previous timeline.
this.timelineChangeController_.on('audioTimelineBehind', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

sounds like we can listen to this event only when dash

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 guess leaving that comment was to point out that this scenario should only happen when DASH.. but I am not sure if it hurts to handle it in any case.

I can probably make that more clear

Copy link
Contributor

Choose a reason for hiding this comment

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

I mean, if this code is explicitly intended to handle a dash-specific case, why should we run it for HLS (and potentially impact HLS playback)

I think we should guard it with if statement

// are on the same timeline.
const newTime = segmentInfo.segment.syncInfo.end + 0.01;

this.tech_.setCurrentTime(newTime);
Copy link
Contributor

Choose a reason for hiding this comment

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

We buffer segments ahead of time. This will jump ahead of what a user sees on the screen at the moment of the jump. Is that expected?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In this scenario, I believe what the user will see at the moment of the jump is a loading screen. This is because the segments that should be playing are not loaded to due this timeline inconsistency.

In this case, I think the jump is OK, but let me know if I am off there.

Copy link
Contributor

@dzianis-dashkevich dzianis-dashkevich Aug 6, 2024

Choose a reason for hiding this comment

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

This is because the segments that should be playing are not loaded to due this timeline inconsistency.

Yeah, that is what I am trying to say; the segment you are loading is around bufferedEnd, while what users see is around currentTime. We do not load segments that should be playing right now, in most cases, we are loading future segments (ahead of time).

we load segments around currentTime only when we are switching rendition.

Copy link
Contributor

@dzianis-dashkevich dzianis-dashkevich Aug 6, 2024

Choose a reason for hiding this comment

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

I guess we should probably check whether currentTime === bufferedEnd, and we are really stuck so we can jump ahead. I suspect we should already have similar logic in the playback watcher...

return true;
}

return false;
Copy link
Contributor

Choose a reason for hiding this comment

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

you can simply:
return hasPendingTimelineChanges && pendingAudioTimelineChange.to < pendingMainTimelineChange.to;

@wseymour15 wseymour15 marked this pull request as ready for review August 7, 2024 21:35
Copy link
Contributor

@adrums86 adrums86 left a comment

Choose a reason for hiding this comment

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

I really like how this ended up, great suggestions @dzianis-dashkevich and fantastic execution @wseymour15 , especially consolidating the logic around checkAndFixTimelines, that leaves us a cleaner way to add other "corrections" for edge cases here if necessary.

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