mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-16 16:16:40 +03:00
2db061d654
Co-authored-by: Wojciech Tyczyński <tykus160@gmail.com>
66 lines
2.0 KiB
JavaScript
66 lines
2.0 KiB
JavaScript
/*! @license
|
|
* Shaka Player
|
|
* Copyright 2026 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
goog.provide('shaka.msf.MSFPresentationTimeline');
|
|
|
|
goog.require('shaka.media.PresentationTimeline');
|
|
|
|
|
|
/**
|
|
* A PresentationTimeline variant for MoQ/MSF live streams.
|
|
*
|
|
* Unlike the standard timeline, the live edge is derived directly from the
|
|
* latest known segment end time rather than from wall-clock arithmetic.
|
|
* This is correct for MoQ because:
|
|
* 1. The server delivers from the live edge; segment timestamps ARE the
|
|
* truth.
|
|
* 2. There is no encoder/clock drift to compensate for.
|
|
*
|
|
* @extends {shaka.media.PresentationTimeline}
|
|
* @export
|
|
* @final
|
|
*/
|
|
// eslint-disable-next-line @stylistic/max-len
|
|
shaka.msf.MSFPresentationTimeline = class extends shaka.media.PresentationTimeline {
|
|
constructor() {
|
|
// presentationStartTime=null avoids wall-clock live edge in base class.
|
|
// delay=0 because MoQ targets minimum latency.
|
|
// maxSegmentDuration=0 because the segments can be very small.
|
|
super(/* presentationStartTime= */ null, /* delay= */ 0,
|
|
/* autoCorrectDrift= */ false, /* maxSegmentDuration= */ 0);
|
|
}
|
|
|
|
/**
|
|
* For MoQ live: the availability end IS the latest segment end time.
|
|
* No wall-clock arithmetic needed.
|
|
* @override
|
|
* @export
|
|
*/
|
|
getSegmentAvailabilityEnd() {
|
|
if (!this.isDynamic()) {
|
|
return super.getSegmentAvailabilityEnd();
|
|
}
|
|
const maxSegmentEndTime = this.getMaxSegmentEndTime();
|
|
return maxSegmentEndTime != null ? maxSegmentEndTime : 0;
|
|
}
|
|
|
|
/**
|
|
* Zero seek range: the availability window is exactly one segment wide.
|
|
* Users cannot seek back on Live.
|
|
* @override
|
|
* @export
|
|
*/
|
|
getSegmentAvailabilityStart() {
|
|
if (!this.isDynamic()) {
|
|
return super.getSegmentAvailabilityStart();
|
|
}
|
|
// Keep one segment of headroom so the player never falls out of range
|
|
// due to the 250ms onPollWindow_ tick.
|
|
return Math.max(0,
|
|
this.getSegmentAvailabilityEnd() - this.getMaxSegmentDuration());
|
|
}
|
|
};
|