import { effect } from "../../core/signals/effect.js"; //#region src/playback/primitives/segment-load-pipeline.ts /** * Base-step view of the loader's own wiring. `createSegmentLoaderActor` folds its * `sourceBufferActor` + `fetch` into the threaded `config` so base steps read them * from the uniform passthrough — present whether the loader runs inside a composition * or standalone. `config` is loose (`object`), so assert the shape here (one cast, like * relocation's `containerSlot`). */ function stepWiring(deps) { return deps.config; } /** * Resolves when the SourceBufferActor snapshot reaches 'idle'. * Rejects if the signal is aborted or the actor is destroyed. * * Used to sequence SourceBufferActor operations without awaiting send() * directly — send() is fire-and-forget; callers observe completion via * state transition. */ function waitForIdle(snapshot, signal) { return new Promise((resolve, reject) => { if (snapshot.get().value === "idle") { resolve(); return; } if (snapshot.get().value === "destroyed") { reject(new DOMException("Aborted", "AbortError")); return; } if (signal.aborted) { reject(signal.reason); return; } let stop; const cleanup = (fn) => { stop?.(); signal.removeEventListener("abort", onAbort); fn(); }; const onAbort = () => cleanup(() => reject(signal.reason)); stop = effect(() => { const value = snapshot.get().value; if (value === "idle") cleanup(resolve); else if (value === "destroyed") cleanup(() => reject(new DOMException("Aborted", "AbortError"))); }); signal.addEventListener("abort", onAbort, { once: true }); }); } /** Build the SourceBuffer message a completed frame dispatches. `fetchStep` always precedes `dispatchStep` in append pipelines, so `data` is set by now. */ function toMessage({ op, data, meta }) { switch (op.type) { case "remove": return op; case "append-init": return { type: "append-init", data, meta: op.meta }; case "append-segment": return { type: "append-segment", data, meta: meta ?? op.meta }; } } /** * Fetch this op's bytes into the frame. Init segments need the full body * (`minChunkSize: Infinity`) before appending; media segments stream so chunks * append as they arrive. Awaiting headers eagerly also starts the HTTP * connection (and records the fetch in observers like tests). */ const fetchStep = async (frame, signal, deps) => { const { op } = frame; if (op.type === "remove") return; const { fetch } = stepWiring(deps); frame.data = await fetch(op, op.type === "append-init" ? { signal, minChunkSize: Infinity } : { signal }); }; /** Dispatch the frame's message to the SourceBufferActor and await its return to idle. */ const dispatchStep = async (frame, signal, deps) => { const { sourceBufferActor } = stepWiring(deps); sourceBufferActor.send(toMessage(frame)); await waitForIdle(sourceBufferActor.snapshot, signal); }; /** Tier 0 default: fetch (for ops that carry bytes) then dispatch. No relocation vocabulary. */ const DEFAULT_MESSAGE_PIPELINES = () => ({ remove: [dispatchStep], "append-init": [fetchStep, dispatchStep], "append-segment": [fetchStep, dispatchStep] }); //#endregion export { DEFAULT_MESSAGE_PIPELINES, dispatchStep, fetchStep }; //# sourceMappingURL=segment-load-pipeline.js.map