fix(observation): admit bounded LAB chunk coverage
This commit is contained in:
@@ -46,6 +46,8 @@ export interface RerunPlaybackState {
|
||||
playing: boolean;
|
||||
/** Latest session-time value currently available to the browser receiver. */
|
||||
bufferedEndNs: number | null;
|
||||
/** Declared first session-time value, when the archive descriptor provides it. */
|
||||
expectedStartNs: number | null;
|
||||
/** Declared final session-time value, when the archive descriptor provides it. */
|
||||
expectedEndNs: number | null;
|
||||
/** Download progress in the closed interval 0..1, or null without a valid expectation. */
|
||||
@@ -182,6 +184,7 @@ export function createRecordedOpenWatchdog<T>({
|
||||
|
||||
export interface RecordedPlaybackBufferState {
|
||||
bufferedEndNs: number | null;
|
||||
expectedStartNs: number | null;
|
||||
expectedEndNs: number | null;
|
||||
bufferProgress: number | null;
|
||||
fullyBuffered: boolean;
|
||||
@@ -214,6 +217,7 @@ export function recordedPlaybackBufferState(
|
||||
if (expectedTimelineEndSeconds === undefined) {
|
||||
return {
|
||||
bufferedEndNs,
|
||||
expectedStartNs: null,
|
||||
expectedEndNs: null,
|
||||
bufferProgress: null,
|
||||
fullyBuffered: usableRange !== null,
|
||||
@@ -222,6 +226,7 @@ export function recordedPlaybackBufferState(
|
||||
if (!Number.isFinite(expectedTimelineEndSeconds) || expectedTimelineEndSeconds < 0) {
|
||||
return {
|
||||
bufferedEndNs,
|
||||
expectedStartNs: null,
|
||||
expectedEndNs: null,
|
||||
bufferProgress: null,
|
||||
fullyBuffered: false,
|
||||
@@ -240,21 +245,32 @@ export function recordedPlaybackBufferState(
|
||||
) {
|
||||
return {
|
||||
bufferedEndNs,
|
||||
expectedStartNs: null,
|
||||
expectedEndNs: null,
|
||||
bufferProgress: null,
|
||||
fullyBuffered: false,
|
||||
};
|
||||
}
|
||||
// Rerun split preserves whole boundary chunks so that all generated splits
|
||||
// still sum exactly to the source recording. A verified bounded artifact can
|
||||
// therefore begin slightly before its declared operator window. Admission
|
||||
// requires coverage of the declared window, not byte-chunk boundary equality.
|
||||
const fullyBuffered = usableRange !== null &&
|
||||
Math.abs(usableRange.min - expectedStartNs) <= BUFFER_END_TOLERANCE_NS &&
|
||||
Math.abs(usableRange.max - expectedEndNs) <= BUFFER_END_TOLERANCE_NS;
|
||||
usableRange.min <= expectedStartNs + BUFFER_END_TOLERANCE_NS &&
|
||||
usableRange.max >= expectedEndNs - BUFFER_END_TOLERANCE_NS;
|
||||
const expectedDurationNs = expectedEndNs - expectedStartNs;
|
||||
const bufferProgress = bufferedEndNs === null
|
||||
? 0
|
||||
: expectedDurationNs <= 0
|
||||
? (fullyBuffered ? 1 : 0)
|
||||
: Math.min(1, Math.max(0, (bufferedEndNs - expectedStartNs) / expectedDurationNs));
|
||||
return { bufferedEndNs, expectedEndNs, bufferProgress, fullyBuffered };
|
||||
return {
|
||||
bufferedEndNs,
|
||||
expectedStartNs,
|
||||
expectedEndNs,
|
||||
bufferProgress,
|
||||
fullyBuffered,
|
||||
};
|
||||
}
|
||||
|
||||
/** A recorded viewport is publishable only after its declared range is complete. */
|
||||
@@ -272,9 +288,19 @@ export function recordedPlaybackRangeWhenReady(
|
||||
buffer: RecordedPlaybackBufferState,
|
||||
artifactVerified: boolean,
|
||||
): { min: number; max: number } | null {
|
||||
return artifactVerified && buffer.fullyBuffered && isUsableRecordedPlaybackRange(rangeNs)
|
||||
? rangeNs
|
||||
: null;
|
||||
if (
|
||||
!artifactVerified ||
|
||||
!buffer.fullyBuffered ||
|
||||
!isUsableRecordedPlaybackRange(rangeNs)
|
||||
) return null;
|
||||
return {
|
||||
min: buffer.expectedStartNs === null
|
||||
? rangeNs.min
|
||||
: Math.max(rangeNs.min, buffer.expectedStartNs),
|
||||
max: buffer.expectedEndNs === null
|
||||
? rangeNs.max
|
||||
: Math.min(rangeNs.max, buffer.expectedEndNs),
|
||||
};
|
||||
}
|
||||
|
||||
/** Do not mount host timeline controls while a recorded generation is partial. */
|
||||
@@ -1076,6 +1102,7 @@ export function RerunViewport({
|
||||
...(followLive
|
||||
? {
|
||||
bufferedEndNs: rangeNs?.max ?? null,
|
||||
expectedStartNs: null,
|
||||
expectedEndNs: null,
|
||||
bufferProgress: null,
|
||||
fullyBuffered: true,
|
||||
@@ -1096,7 +1123,7 @@ export function RerunViewport({
|
||||
emitPlayback({ playing });
|
||||
},
|
||||
jumpToEnd: () => {
|
||||
const range = viewer.get_time_range(event.recording_id, timeline);
|
||||
const range = playbackState?.rangeNs;
|
||||
if (!range) return;
|
||||
viewer.set_current_time(event.recording_id, timeline, range.max);
|
||||
emitPlayback({ rangeNs: range, currentNs: range.max, playing: false });
|
||||
@@ -1151,7 +1178,9 @@ export function RerunViewport({
|
||||
viewer.set_playing(event.recording_id, true);
|
||||
},
|
||||
initialPlaybackStartSeconds === undefined
|
||||
? undefined
|
||||
? expectedTimelineStartSeconds === undefined
|
||||
? undefined
|
||||
: expectedTimelineStartSeconds * 1_000_000_000
|
||||
: initialPlaybackStartSeconds * 1_000_000_000,
|
||||
);
|
||||
if (autoplayStarted) {
|
||||
@@ -1167,6 +1196,7 @@ export function RerunViewport({
|
||||
...(followLive
|
||||
? {
|
||||
bufferedEndNs: rangeNs?.max ?? null,
|
||||
expectedStartNs: null,
|
||||
expectedEndNs: null,
|
||||
bufferProgress: null,
|
||||
fullyBuffered: true,
|
||||
|
||||
Reference in New Issue
Block a user