fix(lab): make recorded replay seek-safe

This commit is contained in:
DCCONSTRUCTIONS
2026-08-24 02:15:30 +03:00
parent 7400fe2fd7
commit 992c5a8b74
12 changed files with 1096 additions and 287 deletions
@@ -9,6 +9,8 @@ let fetchRecordedMediaArchive;
let recordedMediaPresentationState;
let recordedMediaSeekableCoverage;
let recordedMediaFragmentUrl;
let recordedMediaDecodeStartSequence;
let recordedMediaSegmentAppendOrder;
before(async () => {
server = await createServer({
@@ -21,6 +23,8 @@ before(async () => {
recordedMediaPresentationState,
recordedMediaSeekableCoverage,
recordedMediaFragmentUrl,
recordedMediaDecodeStartSequence,
recordedMediaSegmentAppendOrder,
} = await server.ssrLoadModule("/src/components/RecordedFmp4Player.tsx"));
});
@@ -29,6 +33,7 @@ after(async () => {
});
function fixture({ byteLength = 36_000_000_000 } = {}) {
const segmentCount = 1_501;
const manifestUrl = "/api/v1/observation-sessions/session-1/media/camera-1/manifest";
const generation = "a".repeat(64);
const streamUrl = manifestUrl.replace(
@@ -36,7 +41,7 @@ function fixture({ byteLength = 36_000_000_000 } = {}) {
`/epochs/1/recording.mp4?generation=${generation}`,
);
const manifest = {
schema_version: "missioncore.observation-recorded-media/v3",
schema_version: "missioncore.observation-recorded-media/v4",
source_id: "recorded.camera.camera-1",
generation_sha256: generation,
byte_length: byteLength,
@@ -50,6 +55,12 @@ function fixture({ byteLength = 36_000_000_000 } = {}) {
media_type: 'video/mp4; codecs="avc1.640028"',
byte_length: byteLength,
stream_url: streamUrl,
segment_count: segmentCount,
random_access_sequences: [1, 1491, 1501],
segment_end_times_seconds: Array.from(
{ length: segmentCount },
(_value, index) => ((index + 1) * 36_000) / segmentCount,
),
}],
};
const source = {
@@ -92,6 +103,8 @@ test("multi-hour camera admission fetches only its compact generation-bound mani
assert.deepEqual(requested, [source.manifestUrl]);
assert.equal(archive.byteLength, 36_000_000_000);
assert.equal(archive.manifest.epochs[0].streamUrl, streamUrl);
assert.equal(archive.manifest.epochs[0].segmentCount, 1_501);
assert.deepEqual(archive.manifest.epochs[0].randomAccessSequences, [1, 1491, 1501]);
});
test("first camera manifest request rejects a replaced generation", async () => {
@@ -154,8 +167,16 @@ test("recorded player keeps full-archive range fallback and uses bounded generat
assert.match(source, /video\.src\s*=\s*descriptor\.streamUrl/);
assert.doesNotMatch(source, /new Blob\(/);
assert.match(source, /new MediaSource\(\)/);
assert.match(source, /segmentSequence \+ 36/);
assert.match(source, /RECORDED_MEDIA_SEGMENTS_AHEAD = 36/);
assert.match(source, /pumpRecordedSegmentWindow/);
assert.match(source, /waitForRecordedVideoTarget/);
assert.match(source, /removeRecordedMediaRange/);
assert.equal(recordedMediaDecodeStartSequence([1, 1491, 1501], 1500), 1491);
assert.deepEqual(
recordedMediaSegmentAppendOrder(new Set([1491, 1492]), 1491, 1500),
[1493, 1494, 1495, 1496, 1497, 1498, 1499, 1500],
);
const { manifest, generation } = fixture();
const epoch = {
@@ -165,6 +186,9 @@ test("recorded player keeps full-archive range fallback and uses bounded generat
mediaType: manifest.epochs[0].media_type,
byteLength: manifest.epochs[0].byte_length,
streamUrl: manifest.epochs[0].stream_url,
segmentCount: manifest.epochs[0].segment_count,
randomAccessSequences: manifest.epochs[0].random_access_sequences,
segmentEndTimesSeconds: manifest.epochs[0].segment_end_times_seconds,
};
assert.equal(
recordedMediaFragmentUrl(epoch, generation, "init"),