import type { WebcamObserverConfig } from "./webcam-observer.js"; import type { PhotoCaptureTiming, RecordingChunkTiming, } from "./media-capture-timing.js"; /** * Add the SDK upload callbacks to a webcam observer config while allocating * media identities outside the observer. A webcam observer is replaced when * the camera changes, and each fresh observer starts its local counters at 1; * the outer allocators keep server-facing photo/chunk numbers monotonic for the * whole SDK instance so post-switch media cannot be mistaken for a replay. */ export function wrapWebcamCfgWithUploader( cfg: boolean | WebcamObserverConfig, allocatePhotoNumber: () => number, allocateRecordingChunkNumber: () => number, photoUploadCallback: ( photoNumber: number, blob: Blob, timing: PhotoCaptureTiming, ) => void, recordingUploadCallback: ( chunkNumber: number, blob: Blob, timing: RecordingChunkTiming, ) => void, ): WebcamObserverConfig { if (cfg === true) { return { photos: { onPhotoReady: (_observerNumber, blob, timing) => { photoUploadCallback(allocatePhotoNumber(), blob, timing); }, }, }; } if (typeof cfg !== "object") return {}; const base: WebcamObserverConfig = { ...cfg }; const rawPhotos = cfg.photos; if (rawPhotos === true) { base.photos = { onPhotoReady: (_observerNumber, blob, timing) => { photoUploadCallback(allocatePhotoNumber(), blob, timing); }, }; } else if (rawPhotos && typeof rawPhotos === "object") { const customer = rawPhotos.onPhotoReady; base.photos = { ...rawPhotos, onPhotoReady: (_observerNumber, blob, timing) => { const photoNumber = allocatePhotoNumber(); try { customer?.(photoNumber, blob, timing); } catch { // A host callback must never interrupt the SDK upload path. } photoUploadCallback(photoNumber, blob, timing); }, }; } const rawRecording = cfg.recording; if (rawRecording === true) { base.recording = { onChunkReady: (_observerNumber, blob, timing) => { recordingUploadCallback(allocateRecordingChunkNumber(), blob, timing); }, }; } else if (rawRecording && typeof rawRecording === "object") { const customer = rawRecording.onChunkReady; base.recording = { ...rawRecording, onChunkReady: (_observerNumber, blob, timing) => { const chunkNumber = allocateRecordingChunkNumber(); try { customer?.(chunkNumber, blob, timing); } catch { // A host callback must never interrupt the SDK upload path. } recordingUploadCallback(chunkNumber, blob, timing); }, }; } return base; }