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

When seeking to position where's a gap - stream freezes #3808

Closed
5 tasks done
Zahoq opened this issue Nov 9, 2021 · 16 comments
Closed
5 tasks done

When seeking to position where's a gap - stream freezes #3808

Zahoq opened this issue Nov 9, 2021 · 16 comments
Assignees
Labels
Awaiting Feedback Bug stale To be used by automatic issue staling and closing to indicate that this issue is about to be closed
Milestone

Comments

@Zahoq
Copy link

Zahoq commented Nov 9, 2021

Environment
  • Link to playable MPD file:
    MPD has a termination date so I'll copy its body:
    GlobalManifest.txt

  • Dash.js version: 4.1.0

  • Browser name/version: Chrome 95, Tizen 5

  • OS name/version: Mac 11.6 BigSur

Steps to reproduce

set playback position to 0 on stream where there's a gap at the beginning.

Observed behavior

If there's a gap at the beginning of playback, playback freezes after seeking to position 0. GapController doesn't skip gap as it's suspended while seeking. In logs below you can see that gap is present in range 0 - 2.475.

I've verified a workaround that modifies GapController _shouldIgnoreSeekingState to return true by default. After that seeking to position 0 properly continues playback from ~2.475.

Console output
main.45af4666.chunk.js:1 (Player) INFO: restart main
main.45af4666.chunk.js:1 (PlaybackController) INFO: changeParameters {position: 0}
2.e02ea1c3.chunk.js:2 [1166974][PlaybackController] Requesting seek to time: 0 
main.45af4666.chunk.js:1 (VideojsNitroxPlayer) ERROR: dashjs send event: seeking
2.e02ea1c3.chunk.js:2 [1167048][PlaybackController] Seeking to: 0 
2.e02ea1c3.chunk.js:2 [1167059][FragmentModel][video] abort requests 
2.e02ea1c3.chunk.js:2 [1167076][StreamProcessor][video] onFragmentLoadingAbandoned request: http://eu-north-bks400.schange.com/bpk-token/agkzofmi5aaaaaaaaq3vw5caaaaaaaaaaaaod1ehbkomebrg/dash/NBCSN-video=998000-98180858114303.dash?X-ServiceId=service has been aborted 
2.e02ea1c3.chunk.js:2 [1167118][FragmentModel][audio] abort requests 
2.e02ea1c3.chunk.js:2 [1167139][BufferController][video] video: Removing buffer from: 30 to 39.011 
2.e02ea1c3.chunk.js:2 [1167153][BufferController][audio] audio: Removing buffer from: 30 to 40.5 
main.45af4666.chunk.js:1 (VideojsNitroxPlayer) ERROR: dashjs sent event: waiting
2.e02ea1c3.chunk.js:2 [1167229][PlaybackController] Native video element event: waiting 
2.e02ea1c3.chunk.js:2 [1167232][BufferController][video] onRemoved buffer from: 30 to 39.011 
2.e02ea1c3.chunk.js:2 [1167244][BufferController][video] Buffered range: 8.481 - 30.002, currentTime =  0 
2.e02ea1c3.chunk.js:2 [1167256][AbrController] [video] switching from buffer occupancy to throughput ABR rule (buffer: 0.000). 
2.e02ea1c3.chunk.js:2 [1167272][SourceBufferSink][video] Updated append window for video. Set start to 0 and end to 7205.992834000001 
2.e02ea1c3.chunk.js:2 [1167289][BufferController][audio] onRemoved buffer from: 30 to 40.5 
2.e02ea1c3.chunk.js:2 [1167303][BufferController][audio] Buffered range: 0 - 30.016, currentTime =  0 
2.e02ea1c3.chunk.js:2 [1167314][SourceBufferSink][audio] Updated append window for audio. Set start to 0 and end to 7205.992834000001 
2.e02ea1c3.chunk.js:2 [1167335][ScheduleController][video] Quality has changed, get init request for representationid = video=998000 
2.e02ea1c3.chunk.js:2 [1167446][BufferController][video] Append Init fragment video  with representationId: video=998000  and quality: 1 , data size: 730 
2.e02ea1c3.chunk.js:2 [1167459][StreamProcessor][video] OnFragmentLoadingCompleted for stream id 1 and media type video - Url: http://eu-north-bks400.schange.com/bpk-token/agkzofmi5aaaaaaaaq3vw5caaaaaaaaaaaaod1ehbkomebrg/dash/NBCSN-video=998000.dash?BKSVAR_ARCHIVE_SEGMENT=37878&X-ServiceId=service  
2.e02ea1c3.chunk.js:2 [1167493][ScheduleController][video] Appended bytes for video and stream id 1 
2.e02ea1c3.chunk.js:2 [1167503][ScheduleController][video] [video] lastInitializedRepresentationInfo changed to 1 
2.e02ea1c3.chunk.js:2 [1167520][ScheduleController][video] Media segment needed for video and stream id 1 
2.e02ea1c3.chunk.js:2 [1167531][DashHandler][video] Index for time 0 is 0 
2.e02ea1c3.chunk.js:2 [1167543][StreamProcessor][video] Next fragment request url for stream id 1 and media type video is http://eu-north-bks400.schange.com/bpk-token/agkzofmi5aaaaaaaaq3vw5caaaaaaaaaaaaod1ehbkomebrg/dash/NBCSN-video=998000-98180855952143.dash?X-ServiceId=service 
2.e02ea1c3.chunk.js:2 [1167717][StreamProcessor][video] OnFragmentLoadingCompleted for stream id 1 and media type video - Url: http://eu-north-bks400.schange.com/bpk-token/agkzofmi5aaaaaaaaq3vw5caaaaaaaaaaaaod1ehbkomebrg/dash/NBCSN-video=998000-98180855952143.dash?X-ServiceId=service  
2.e02ea1c3.chunk.js:2 [1167756][BufferController][video] Buffered range: 2.475 - 4.477, currentTime =  0 
2.e02ea1c3.chunk.js:2 [1167769][BufferController][video] Buffered range: 8.481 - 30.002, currentTime =  0 
2.e02ea1c3.chunk.js:2 [1167809][ScheduleController][video] Appended bytes for video and stream id 1 
2.e02ea1c3.chunk.js:2 [1167838][ScheduleController][video] Media segment needed for video and stream id 1 
2.e02ea1c3.chunk.js:2 [1167852][StreamProcessor][video] Next fragment request url for stream id 1 and media type video is http://eu-north-bks400.schange.com/bpk-token/agkzofmi5aaaaaaaaq3vw5caaaaaaaaaaaaod1ehbkomebrg/dash/NBCSN-video=998000-98180856072263.dash?X-ServiceId=service 
2.e02ea1c3.chunk.js:2 [1168020][StreamProcessor][video] OnFragmentLoadingCompleted for stream id 1 and media type video - Url: http://eu-north-bks400.schange.com/bpk-token/agkzofmi5aaaaaaaaq3vw5caaaaaaaaaaaaod1ehbkomebrg/dash/NBCSN-video=998000-98180856072263.dash?X-ServiceId=service  
2.e02ea1c3.chunk.js:2 [1168066][BufferController][video] Buffered range: 2.475 - 6.479, currentTime =  0 
2.e02ea1c3.chunk.js:2 [1168081][BufferController][video] Buffered range: 8.481 - 30.002, currentTime =  0 
2.e02ea1c3.chunk.js:2 [1168125][ScheduleController][video] Appended bytes for video and stream id 1 
2.e02ea1c3.chunk.js:2 [1168161][AbrController] Stream ID: 1 [video] switch from 1 to 0/1 (buffer: 0) "InsufficientBufferRule: being conservative to avoid immediate rebuffering" 
2.e02ea1c3.chunk.js:2 [1168181][StreamProcessor][video] Preparing quality switch for type video 
2.e02ea1c3.chunk.js:2 [1168202][FragmentModel][video] abort requests 
2.e02ea1c3.chunk.js:2 [1168235][SwitchHistoryRule] Switch history rule index: 0 samples: 8 drops: 1 
2.e02ea1c3.chunk.js:2 [1168253][ScheduleController][video] Quality has changed, get init request for representationid = video=499000 
2.e02ea1c3.chunk.js:2 [1168310][BufferController][video] Append Init fragment video  with representationId: video=499000  and quality: 0 , data size: 729 
2.e02ea1c3.chunk.js:2 [1168334][StreamProcessor][video] OnFragmentLoadingCompleted for stream id 1 and media type video - Url: http://eu-north-bks400.schange.com/bpk-token/agkzofmi5aaaaaaaaq3vw5caaaaaaaaaaaaod1ehbkomebrg/dash/NBCSN-video=499000.dash?BKSVAR_ARCHIVE_SEGMENT=37878&X-ServiceId=service  
2.e02ea1c3.chunk.js:2 [1168435][ScheduleController][video] Appended bytes for video and stream id 1 
2.e02ea1c3.chunk.js:2 [1168455][ScheduleController][video] [video] lastInitializedRepresentationInfo changed to 0 
2.e02ea1c3.chunk.js:2 [1168481][ScheduleController][video] Media segment needed for video and stream id 1 
2.e02ea1c3.chunk.js:2 [1168499][StreamProcessor][video] Next fragment request url for stream id 1 and media type video is http://eu-north-bks400.schange.com/bpk-token/agkzofmi5aaaaaaaaq3vw5caaaaaaaaaaaaod1ehbkomebrg/dash/NBCSN-video=499000-98180856192383.dash?X-ServiceId=service 
2.e02ea1c3.chunk.js:2 [1168644][StreamProcessor][video] OnFragmentLoadingCompleted for stream id 1 and media type video - Url: http://eu-north-bks400.schange.com/bpk-token/agkzofmi5aaaaaaaaq3vw5caaaaaaaaaaaaod1ehbkomebrg/dash/NBCSN-video=499000-98180856192383.dash?X-ServiceId=service  
2.e02ea1c3.chunk.js:2 [1168693][BufferController][video] Buffered range: 2.475 - 30.002, currentTime =  0 
2.e02ea1c3.chunk.js:2 [1168757][ScheduleController][video] Appended bytes for video and stream id 1 
2.e02ea1c3.chunk.js:2 [1168804][SwitchHistoryRule] Switch history rule index: 0 samples: 8 drops: 1 
2.e02ea1c3.chunk.js:2 [1168826][ScheduleController][video] Media segment needed for video and stream id 1 
2.e02ea1c3.chunk.js:2 [1168849][StreamProcessor][video] Next fragment request url for stream id 1 and media type video is http://eu-north-bks400.schange.com/bpk-token/agkzofmi5aaaaaaaaq3vw5caaaaaaaaaaaaod1ehbkomebrg/dash/NBCSN-video=499000-98180856312503.dash?X-ServiceId=service 
2.e02ea1c3.chunk.js:2 [1168991][StreamProcessor][video] OnFragmentLoadingCompleted for stream id 1 and media type video - Url: http://eu-north-bks400.schange.com/bpk-token/agkzofmi5aaaaaaaaq3vw5caaaaaaaaaaaaod1ehbkomebrg/dash/NBCSN-video=499000-98180856312503.dash?X-ServiceId=service  
2.e02ea1c3.chunk.js:2 [1169057][BufferController][video] Buffered range: 2.475 - 30.002, currentTime =  0 
2.e02ea1c3.chunk.js:2 [1169125][ScheduleController][video] Appended bytes for video and stream id 1 
2.e02ea1c3.chunk.js:2 [1169157][SwitchHistoryRule] Switch history rule index: 0 samples: 8 drops: 1 
2.e02ea1c3.chunk.js:2 [1169180][ScheduleController][video] Media segment needed for video and stream id 1 
2.e02ea1c3.chunk.js:2 [1169205][StreamProcessor][video] Next fragment request url for stream id 1 and media type video is http://eu-north-bks400.schange.com/bpk-token/agkzofmi5aaaaaaaaq3vw5caaaaaaaaaaaaod1ehbkomebrg/dash/NBCSN-video=499000-98180856432623.dash?X-ServiceId=service 
2.e02ea1c3.chunk.js:2 [1169329][StreamProcessor][video] OnFragmentLoadingCompleted for stream id 1 and media type video - Url: http://eu-north-bks400.schange.com/bpk-token/agkzofmi5aaaaaaaaq3vw5caaaaaaaaaaaaod1ehbkomebrg/dash/NBCSN-video=499000-98180856432623.dash?X-ServiceId=service  
Expected behavior

Dont freeze playback when seeking to the middle of gap.

Additional questions:

  1. Is there some kind of event that informs about failure of buffer fetch? I wanted to fix that issue by checking if specific range that cannot be fetched is a range where user wants to seek. If so, skip that gap.
  2. what if there's a significant gap in the middle of asset lets say 50s - 60s and user seeks to 55s, will issue reproduce or there's an edge case with gap at the beginning of stream?
@Zahoq Zahoq added the Bug label Nov 9, 2021
@dsilhavy
Copy link
Collaborator

dsilhavy commented Nov 9, 2021

@Zahoq We do have a workaround for that in place. This workaround was added shortly before the release of 4.1.0 which is why we disabled it by default. The basic idea is to adjust the seek target by seeking close to the target time. This is only supported for static content as of today. Please try by enabling it as follows:

player.updateSettings({streaming: {gaps: {enableSeekFix: true}}})

It would be great if you can share your results here. If this proves to be stable we will consider enabling it by default.

@Zahoq
Copy link
Author

Zahoq commented Nov 10, 2021

@dsilhavy we're already using enableSeekFix workaround. Issue reproduces with enableSeekFix set to true.

@dsilhavy
Copy link
Collaborator

Can you please share a playable version/link to the stream then we can check.

Also please check if this still occurs with the latest development branch, specifically after this fix: 5965ab6

@dsilhavy dsilhavy self-assigned this Nov 10, 2021
@Zahoq
Copy link
Author

Zahoq commented Nov 16, 2021

@dsilhavy my apologies for long delay between responses. Sadly I am unable to provide link to stream, it requires established session with our content provider servers. I'll try to prepare something, however it will take some time.

I've verified fix 5965ab6 , it didn't solve the issue. Let me investigate it further, I'll provide more details.

@Zahoq
Copy link
Author

Zahoq commented Nov 18, 2021

@dsilhavy investigation led me to conclusion that issue occurs because of the missing range that contains our seekTarget. I've noticed that BufferController has a function called _adjustSeekTarget, which sounds like a good place for further expansion. Please check fix proposal:
https://github.com/Zahoq/dash.js/commit/183d13ad871865135fd366006fe95618693c6aad
Could you please verify if my approach to permanently missing range at the beginning of the stream is correct? Probably that fix should be wrapped with settings flag like enableSeekDecorrelationFix

So far I've found no issues with that fix, however I still need to test thoroughly seeking far outside fetched buffer.

@dsilhavy
Copy link
Collaborator

Thanks, please issue a pull request with your changes against development. You can add the label "Work in Progress - Don't Merge" to indicate that this is still ongoing. That makes it easier for me to check.

Thank you

@Zahoq
Copy link
Author

Zahoq commented Nov 19, 2021

@dsilhavy please check #3818

@dsilhavy
Copy link
Collaborator

dsilhavy commented Nov 20, 2021

@Zahoq Thanks. I checked your logs and the manifest. For video there is clearly a gap in the manifest as S@t for the first segment is larger than presentationTimeOffset. Consequently what dash.js is doing is also wrong:
2.e02ea1c3.chunk.js:2 [1167531][DashHandler][video] Index for time 0 is 0 is wrong as there is no segment signaled for time 0.

This is exactly what _noMediaRequestGenerated in StreamProcessor was added for. Now the question is why dash.js thinks that there is a suitable segment. I think this is causes by time TimelineSegmentsGetter. Can you please check if https://github.com/Dash-Industry-Forum/dash.js/tree/fix/3808 solves your issue. It includes a fix for the TimelineSegmentsGetter and a small change in _noMediaRequestGenerated.

Please remember to enable enableSeekFix:

gaps: {
     enableSeekFix: true
},

I think your PR is good as well but I would prefer fixing this using the existing logic.

@Zahoq
Copy link
Author

Zahoq commented Nov 24, 2021

@dsilhavy Sadly asset with gap at the beginning went down. I'm waiting for our 3rd party team to bring it back. I should be able to test it tomorrow.

@Zahoq
Copy link
Author

Zahoq commented Nov 26, 2021

@dsilhavy asset with gap at the beginning has been removed from our BO, it will take some time to bring it back to retest this issue:( My team will update this issue once it's retested.

@dsilhavy
Copy link
Collaborator

@Zahoq Thanks for the update, I have merged #3818 to development. We can keep this issue open for now.

@dsilhavy dsilhavy added this to the 4.2.1 milestone Nov 29, 2021
@dsilhavy
Copy link
Collaborator

I will close this for now as the issue is solved in my tests and enableSeekFix is enabled by default with #3832

@bbert
Copy link
Contributor

bbert commented Jan 7, 2022

I have a concern with the modification that has been made in the TimelineSegmentGetter.
Consider the following use case:

  • play a live stream, with SegmentTimeline and manifest updates
  • due to network congestion, playback falls behind dvr window
  • then PlaybackController tries to catch up dvr window (see updateCurrentTime())
  • if in the meantime, while seeking and then first removing current buffered segments (that may take some time on some platforms), the manifest is updated and then dvr window is shifted of one segment, thus no more segment will be available at seeking time (=previous dvr window start)
  • as a consequence, playback is freezed

With previous of TimelineSegmentGetter, the first segment of the dvr window would have been returned then the BufferController would have adjusted the seeking time.

Don't know to fix it yet.
Maybe a solution, for live streams, can be to adjust seek time if no request can be found at initial seek time.
@dsilhavy what do you think?

@bbert bbert reopened this Jan 7, 2022
@dsilhavy
Copy link
Collaborator

@bbert I added a workaround for dynamic SegmentTimeline streams in StreamProcessor . In case no valid request could be generated but a valid request is available ahead of the target seek time then the seek time is adjusted:

else if (isDynamic && representation.segmentInfoType === DashConstants.SEGMENT_TIMELINE) {
    adjustedTime = dashHandler.getValidTimeAheadOfTargetTime(bufferingTime, mediaInfo, representation, settings.get().streaming.gaps.threshold,);
}

Do you think this solves the error?

@stale
Copy link

stale bot commented Oct 8, 2022

This issue has been automatically marked as stale because it has not had recent activity. However, it might still be relevant so please leave a short comment if it should remain open. Otherwise the issue will be closed automatically after two weeks. Thank you for your contributions.

@stale stale bot added the stale To be used by automatic issue staling and closing to indicate that this issue is about to be closed label Oct 8, 2022
@stale
Copy link

stale bot commented Oct 22, 2022

This issue has been automatically closed because no further activity occurred. If you think this issue is still relevant please reopen it or contact @dsilhavy. Thank you for your contributions.

@stale stale bot closed this as completed Oct 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting Feedback Bug stale To be used by automatic issue staling and closing to indicate that this issue is about to be closed
Projects
None yet
Development

No branches or pull requests

3 participants