Milestone v1 (v2.0.0): Mokosh — Session Capture #1
@@ -1,12 +1,19 @@
|
|||||||
import { Logger } from '../shared/logger';
|
import { Logger } from '../shared/logger';
|
||||||
|
import { base64ToBlob } from '../shared/binary';
|
||||||
import type {
|
import type {
|
||||||
Message,
|
Message,
|
||||||
|
TransferredVideoChunk,
|
||||||
VideoChunk,
|
VideoChunk,
|
||||||
SessionMetadata,
|
SessionMetadata,
|
||||||
VideoBufferResponse
|
VideoBufferResponse
|
||||||
} from '../shared/types';
|
} from '../shared/types';
|
||||||
import JSZip from 'jszip';
|
import JSZip from 'jszip';
|
||||||
|
|
||||||
|
// Default MIME applied when a wire chunk somehow lacks a type
|
||||||
|
// field (defense-in-depth: in normal operation the offscreen recorder
|
||||||
|
// always populates it from chunk.data.type). Matches D-20 strict codec.
|
||||||
|
const VIDEO_MIME_FALLBACK = 'video/webm;codecs=vp9';
|
||||||
|
|
||||||
const logger = new Logger('Main');
|
const logger = new Logger('Main');
|
||||||
|
|
||||||
// Состояние
|
// Состояние
|
||||||
@@ -88,6 +95,11 @@ chrome.runtime.onConnect.addListener((port) => {
|
|||||||
// per-request listener installed in getVideoBufferFromOffscreen).
|
// per-request listener installed in getVideoBufferFromOffscreen).
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 2 s budget covers the worst-case round-trip: offscreen base64-encodes
|
||||||
|
// up to ~15 chunks of ~100 KB each (~1.5 MB raw → ~2 MB base64) in
|
||||||
|
// well under 100 ms, post-message + JSON parse adds < 50 ms, leaving
|
||||||
|
// plenty of headroom. Bumping later is cheap if real-world recordings
|
||||||
|
// produce significantly larger buffers; today this is sufficient.
|
||||||
const BUFFER_FETCH_TIMEOUT_MS = 2_000;
|
const BUFFER_FETCH_TIMEOUT_MS = 2_000;
|
||||||
|
|
||||||
async function getVideoBufferFromOffscreen(): Promise<VideoBufferResponse> {
|
async function getVideoBufferFromOffscreen(): Promise<VideoBufferResponse> {
|
||||||
@@ -110,7 +122,30 @@ async function getVideoBufferFromOffscreen(): Promise<VideoBufferResponse> {
|
|||||||
) {
|
) {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
port.onMessage.removeListener(handler);
|
port.onMessage.removeListener(handler);
|
||||||
const chunks = (msg as { chunks?: VideoChunk[] }).chunks ?? [];
|
// D-12 fix: chunks arrive as TransferredVideoChunk[] (base64
|
||||||
|
// string + MIME). Decode each back into a VideoChunk so
|
||||||
|
// mergeVideoChunks keeps operating on real Blobs. See
|
||||||
|
// src/shared/binary.ts and the GREEN block of
|
||||||
|
// tests/offscreen/port-serialization.test.ts.
|
||||||
|
const wireChunks =
|
||||||
|
(msg as { chunks?: TransferredVideoChunk[] }).chunks ?? [];
|
||||||
|
const chunks: VideoChunk[] = [];
|
||||||
|
for (const wire of wireChunks) {
|
||||||
|
try {
|
||||||
|
chunks.push({
|
||||||
|
data: base64ToBlob(wire.data, wire.type || VIDEO_MIME_FALLBACK),
|
||||||
|
timestamp: wire.timestamp,
|
||||||
|
isFirst: wire.isFirst,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
logger.warn(
|
||||||
|
'base64ToBlob failed; skipping chunk',
|
||||||
|
'timestamp:', wire.timestamp,
|
||||||
|
'isFirst:', wire.isFirst,
|
||||||
|
'error:', err,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
resolve({ chunks });
|
resolve({ chunks });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user