mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
139 lines
4.2 KiB
JavaScript
139 lines
4.2 KiB
JavaScript
import { SerialRunner, Task } from "../../../core/tasks/task.js";
|
|
import { createMachineActor } from "../../../core/actors/create-machine-actor.js";
|
|
import { appendSegment } from "../../../media/dom/mse/append-segment.js";
|
|
import { flushBuffer } from "../../../media/dom/mse/buffer-flusher.js";
|
|
import { SEGMENT_TIME_EPSILON } from "../../../media/types/index.js";
|
|
//#region src/playback/actors/dom/source-buffer.ts
|
|
function snapshotBuffered(buffered) {
|
|
const ranges = [];
|
|
for (let i = 0; i < buffered.length; i++) ranges.push({
|
|
start: buffered.start(i),
|
|
end: buffered.end(i)
|
|
});
|
|
return ranges;
|
|
}
|
|
function appendInitTask(message, { getContext, sourceBuffer }) {
|
|
return new Task(async (taskSignal) => {
|
|
const ctx = getContext();
|
|
if (taskSignal.aborted) return ctx;
|
|
await appendSegment(sourceBuffer, message.data);
|
|
return {
|
|
...ctx,
|
|
initTrackId: message.meta.trackId,
|
|
initTrackLanguage: message.meta.language
|
|
};
|
|
});
|
|
}
|
|
function appendSegmentTask(message, { getContext, sourceBuffer, setContext }) {
|
|
return new Task(async (taskSignal) => {
|
|
const ctx = getContext();
|
|
if (taskSignal.aborted) return ctx;
|
|
const { meta } = message;
|
|
const filtered = ctx.segments.filter((s) => Math.abs(s.startTime - meta.startTime) >= SEGMENT_TIME_EPSILON);
|
|
if (!(message.data instanceof ArrayBuffer)) setContext({
|
|
...ctx,
|
|
segments: [...filtered, {
|
|
id: meta.id,
|
|
startTime: meta.startTime,
|
|
duration: meta.duration,
|
|
trackId: meta.trackId,
|
|
...meta.trackBandwidth !== void 0 && { trackBandwidth: meta.trackBandwidth },
|
|
partial: true
|
|
}],
|
|
bufferedRanges: ctx.bufferedRanges
|
|
});
|
|
if (meta.timestampOffset != null && sourceBuffer.timestampOffset !== meta.timestampOffset) sourceBuffer.timestampOffset = meta.timestampOffset;
|
|
await appendSegment(sourceBuffer, message.data, taskSignal);
|
|
return {
|
|
...ctx,
|
|
segments: [...filtered, {
|
|
id: meta.id,
|
|
startTime: meta.startTime,
|
|
duration: meta.duration,
|
|
trackId: meta.trackId,
|
|
...meta.trackBandwidth !== void 0 && { trackBandwidth: meta.trackBandwidth }
|
|
}],
|
|
bufferedRanges: snapshotBuffered(sourceBuffer.buffered)
|
|
};
|
|
});
|
|
}
|
|
function removeTask(message, { getContext, sourceBuffer }) {
|
|
return new Task(async (taskSignal) => {
|
|
const ctx = getContext();
|
|
if (taskSignal.aborted) return ctx;
|
|
await flushBuffer(sourceBuffer, message.start, message.end);
|
|
const bufferedRanges = snapshotBuffered(sourceBuffer.buffered);
|
|
const filtered = ctx.segments.filter((s) => {
|
|
const midpoint = s.startTime + s.duration / 2;
|
|
return bufferedRanges.some((r) => midpoint >= r.start && midpoint < r.end);
|
|
});
|
|
return {
|
|
...ctx,
|
|
segments: filtered,
|
|
bufferedRanges
|
|
};
|
|
});
|
|
}
|
|
const messageTaskFactories = {
|
|
"append-init": appendInitTask,
|
|
"append-segment": appendSegmentTask,
|
|
remove: removeTask
|
|
};
|
|
function messageToTask(message, options) {
|
|
const factory = messageTaskFactories[message.type];
|
|
return factory(message, options);
|
|
}
|
|
function createSourceBufferActor(sourceBuffer, initialContext) {
|
|
const handleError = (e) => {
|
|
if (!(e instanceof Error && e.name === "AbortError")) console.error("SourceBuffer operation failed:", e);
|
|
};
|
|
const onMessage = (msg, { transition, setContext, getContext, runner }) => {
|
|
transition("updating");
|
|
const task = messageToTask(msg, {
|
|
getContext,
|
|
sourceBuffer,
|
|
setContext
|
|
});
|
|
runner.schedule(task).then(setContext, handleError);
|
|
};
|
|
return createMachineActor({
|
|
runner: () => new SerialRunner(),
|
|
initial: "idle",
|
|
context: {
|
|
segments: [],
|
|
bufferedRanges: [],
|
|
initTrackId: void 0,
|
|
...initialContext
|
|
},
|
|
states: {
|
|
idle: { on: {
|
|
"append-init": onMessage,
|
|
"append-segment": onMessage,
|
|
remove: onMessage,
|
|
batch: (msg, { transition, setContext, getContext, runner }) => {
|
|
const { messages } = msg;
|
|
if (messages.length === 0) return;
|
|
transition("updating");
|
|
messages.forEach((msg) => {
|
|
const task = messageToTask(msg, {
|
|
getContext,
|
|
sourceBuffer,
|
|
setContext
|
|
});
|
|
runner.schedule(task).then(setContext, handleError);
|
|
});
|
|
}
|
|
} },
|
|
updating: {
|
|
onSettled: "idle",
|
|
on: { cancel: (_, { runner }) => {
|
|
runner.abortAll();
|
|
} }
|
|
}
|
|
}
|
|
});
|
|
}
|
|
//#endregion
|
|
export { createSourceBufferActor };
|
|
|
|
//# sourceMappingURL=source-buffer.js.map
|