mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
The model timeline (an averageDuration×sequence estimate) could drift from the SourceBuffer's native-PTS timeline across reloads. At ENDLIST the drifted model placed the final segments behind the playhead, so the loader skipped them and end-of-stream's isLastSegmentAppended never satisfied — playback stalled in `waiting`, duration stuck at Infinity, `ended` never fired. Pin the model to ground truth: once a segment is buffered, re-origin the track onto where it actually landed (anchorTrackToBufferedSegment), correlated via bufferedAnchorFor over the buffer actor's DOM-free snapshot. Pin once per track (the offset is constant under no-discontinuity); the parser's now-PDT-exact carry-forward maintains it. The sequence estimate stays the pre-buffer bootstrap. anchorLiveTracks stays DOM-free — the engine injects the resolver from the buffer actors; no timestampOffset (preserves A/V sync). The same pin serves non-zero-PTS VOD. Smoke-tested on a live Mux LL-HLS stream: durationchange → finite duration → plays out → `ended`, no stall. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
34 lines
1.2 KiB
TypeScript
34 lines
1.2 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
||
import { bufferedAnchorFor } from '../buffered-anchor';
|
||
|
||
describe('bufferedAnchorFor', () => {
|
||
it('pairs the leading-edge segment with its actual native-PTS start', () => {
|
||
// Model says the latest segment sits at 110 (+10s long); the buffer's real
|
||
// leading edge is 550 → it actually starts at 540 (a +430 native-PTS offset).
|
||
const anchor = bufferedAnchorFor(
|
||
[
|
||
{ id: 's1', startTime: 100, duration: 10 },
|
||
{ id: 's2', startTime: 110, duration: 10 },
|
||
],
|
||
[{ start: 530, end: 550 }]
|
||
);
|
||
expect(anchor).toEqual({ segmentId: 's2', actualStart: 540 });
|
||
});
|
||
|
||
it('uses the max end across discontiguous ranges', () => {
|
||
const anchor = bufferedAnchorFor(
|
||
[{ id: 's2', startTime: 110, duration: 10 }],
|
||
[
|
||
{ start: 530, end: 545 },
|
||
{ start: 548, end: 552 },
|
||
]
|
||
);
|
||
expect(anchor?.actualStart).toBe(542); // 552 − 10
|
||
});
|
||
|
||
it('returns undefined before anything is buffered', () => {
|
||
expect(bufferedAnchorFor([{ id: 's1', startTime: 0, duration: 10 }], [])).toBeUndefined();
|
||
expect(bufferedAnchorFor([], [{ start: 0, end: 10 }])).toBeUndefined();
|
||
});
|
||
});
|