@videojs/spf 10.0.0-beta.1 → 10.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{adapter-l8iJN_GI.d.ts → adapter-25AtMN8s.d.ts} +34 -4
- package/dist/adapter-25AtMN8s.d.ts.map +1 -0
- package/dist/{adapter-CMw-rvbk.js → adapter-CflgYzjF.js} +198 -154
- package/dist/adapter-CflgYzjF.js.map +1 -0
- package/dist/dom/index.d.ts +1 -23
- package/dist/dom/index.d.ts.map +1 -1
- package/dist/dom/index.js +1 -1
- package/dist/dom/playback-engine/index.d.ts +1 -1
- package/dist/dom/playback-engine/index.js +1 -1
- package/package.json +2 -2
- package/dist/adapter-CMw-rvbk.js.map +0 -1
- package/dist/adapter-l8iJN_GI.d.ts.map +0 -1
|
@@ -345,6 +345,28 @@ interface Actor<Status extends string, Context> {
|
|
|
345
345
|
destroy(): void;
|
|
346
346
|
}
|
|
347
347
|
//#endregion
|
|
348
|
+
//#region src/dom/media/append-segment.d.ts
|
|
349
|
+
/**
|
|
350
|
+
* Segment appender helper.
|
|
351
|
+
*
|
|
352
|
+
* Appends media data (ArrayBuffer or AsyncIterable<Uint8Array> stream) to a
|
|
353
|
+
* SourceBuffer, waiting for `updateend` between calls so the browser can
|
|
354
|
+
* process each append before the next one arrives.
|
|
355
|
+
*/
|
|
356
|
+
/** Data accepted by appendSegment — a full buffer or an async chunk stream. */
|
|
357
|
+
type AppendData = ArrayBuffer | AsyncIterable<Uint8Array>;
|
|
358
|
+
/**
|
|
359
|
+
* Append media data to a SourceBuffer.
|
|
360
|
+
*
|
|
361
|
+
* Accepts either a full ArrayBuffer (single append) or an AsyncIterable of
|
|
362
|
+
* Uint8Array chunks (one append per chunk, in order). Waits for `updateend`
|
|
363
|
+
* between each call so appends are serialized correctly.
|
|
364
|
+
*
|
|
365
|
+
* Errors from the SourceBuffer (`error` event) or from the iterable are
|
|
366
|
+
* propagated as rejections.
|
|
367
|
+
*/
|
|
368
|
+
declare function appendSegment(sourceBuffer: SourceBuffer, data: AppendData, signal?: AbortSignal): Promise<void>;
|
|
369
|
+
//#endregion
|
|
348
370
|
//#region src/dom/media/source-buffer-actor.d.ts
|
|
349
371
|
interface BufferedRange {
|
|
350
372
|
start: number;
|
|
@@ -357,14 +379,14 @@ type AppendSegmentMeta = Pick<Segment, 'id' | 'startTime' | 'duration'> & {
|
|
|
357
379
|
};
|
|
358
380
|
type AppendInitMessage = {
|
|
359
381
|
type: 'append-init';
|
|
360
|
-
data:
|
|
382
|
+
data: AppendData;
|
|
361
383
|
meta: {
|
|
362
384
|
trackId: Track['id'];
|
|
363
385
|
};
|
|
364
386
|
};
|
|
365
387
|
type AppendSegmentMessage = {
|
|
366
388
|
type: 'append-segment';
|
|
367
|
-
data:
|
|
389
|
+
data: AppendData;
|
|
368
390
|
meta: AppendSegmentMeta;
|
|
369
391
|
};
|
|
370
392
|
type RemoveMessage = {
|
|
@@ -381,6 +403,12 @@ interface SourceBufferActorContext {
|
|
|
381
403
|
segments: Array<Pick<Segment, 'id' | 'startTime' | 'duration'> & {
|
|
382
404
|
trackId: Track['id'];
|
|
383
405
|
trackBandwidth?: number;
|
|
406
|
+
/**
|
|
407
|
+
* True while a streaming append is in progress for this segment.
|
|
408
|
+
* The segment's data is partially present in the SourceBuffer.
|
|
409
|
+
* Downstream code must not treat a partial segment as fully buffered.
|
|
410
|
+
*/
|
|
411
|
+
partial?: boolean;
|
|
384
412
|
}>;
|
|
385
413
|
bufferedRanges: BufferedRange[];
|
|
386
414
|
}
|
|
@@ -680,10 +708,12 @@ declare class SpfMedia {
|
|
|
680
708
|
attach(mediaElement: HTMLMediaElement): void;
|
|
681
709
|
detach(): void;
|
|
682
710
|
destroy(): void;
|
|
711
|
+
get preload(): '' | 'none' | 'metadata' | 'auto';
|
|
712
|
+
set preload(value: '' | 'none' | 'metadata' | 'auto');
|
|
683
713
|
get src(): string;
|
|
684
714
|
set src(value: string);
|
|
685
715
|
play(): Promise<void>;
|
|
686
716
|
}
|
|
687
717
|
//#endregion
|
|
688
|
-
export { PresentationAction as a, SourceBufferActor as c,
|
|
689
|
-
//# sourceMappingURL=adapter-
|
|
718
|
+
export { PresentationAction as a, SourceBufferActor as c, Presentation as d, WritableState as f, createPlaybackEngine as i, appendSegment as l, PlaybackEngine as n, EventStream as o, BandwidthState as p, PlaybackEngineConfig as r, loadTextTrackCues as s, SpfMedia as t, TrackSelectionState as u };
|
|
719
|
+
//# sourceMappingURL=adapter-25AtMN8s.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-25AtMN8s.d.ts","names":[],"sources":["../src/core/abr/bandwidth-estimator.ts","../src/core/state/create-state.ts","../src/core/types/index.ts","../src/core/utils/track-selection.ts","../src/core/actor.ts","../src/dom/media/append-segment.ts","../src/dom/media/source-buffer-actor.ts","../src/dom/features/load-text-track-cues.ts","../src/core/events/create-event-stream.ts","../src/core/features/resolve-presentation.ts","../src/core/features/resolve-track.ts","../src/core/features/select-tracks.ts","../src/dom/playback-engine/engine.ts","../src/dom/playback-engine/adapter.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { listen } from "@videojs/utils/dom";
|
|
2
|
-
import { isNil
|
|
2
|
+
import { isNil } from "@videojs/utils/predicate";
|
|
3
3
|
|
|
4
4
|
//#region src/core/state/create-state.ts
|
|
5
5
|
/**
|
|
@@ -1067,6 +1067,53 @@ function isCodecSupported(mimeCodec) {
|
|
|
1067
1067
|
return MediaSource.isTypeSupported(mimeCodec);
|
|
1068
1068
|
}
|
|
1069
1069
|
|
|
1070
|
+
//#endregion
|
|
1071
|
+
//#region src/dom/network/chunked-stream-iterable.ts
|
|
1072
|
+
const DEFAULT_MIN_CHUNK_SIZE = 2 ** 17;
|
|
1073
|
+
/**
|
|
1074
|
+
* Adapts a `ReadableStream<Uint8Array>` (e.g. `response.body`) into an
|
|
1075
|
+
* `AsyncIterable<Uint8Array>` that yields chunks no smaller than
|
|
1076
|
+
* `minChunkSize` bytes. Smaller network chunks are accumulated and yielded
|
|
1077
|
+
* together once the threshold is met. Any remainder is flushed on stream end.
|
|
1078
|
+
*
|
|
1079
|
+
* Errors from the underlying stream propagate naturally — the reader lock is
|
|
1080
|
+
* always released via `finally`.
|
|
1081
|
+
*/
|
|
1082
|
+
var ChunkedStreamIterable = class {
|
|
1083
|
+
minChunkSize;
|
|
1084
|
+
#readableStream;
|
|
1085
|
+
constructor(readableStream, { minChunkSize = DEFAULT_MIN_CHUNK_SIZE } = {}) {
|
|
1086
|
+
this.#readableStream = readableStream;
|
|
1087
|
+
this.minChunkSize = minChunkSize;
|
|
1088
|
+
}
|
|
1089
|
+
async *[Symbol.asyncIterator]() {
|
|
1090
|
+
let pending;
|
|
1091
|
+
const reader = this.#readableStream.getReader();
|
|
1092
|
+
try {
|
|
1093
|
+
while (true) {
|
|
1094
|
+
const { done, value } = await reader.read();
|
|
1095
|
+
if (done) {
|
|
1096
|
+
if (pending) yield pending;
|
|
1097
|
+
break;
|
|
1098
|
+
}
|
|
1099
|
+
pending = pending ? concat(pending, value) : value;
|
|
1100
|
+
if (pending.length >= this.minChunkSize) {
|
|
1101
|
+
yield pending;
|
|
1102
|
+
pending = void 0;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
} finally {
|
|
1106
|
+
reader.releaseLock();
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
};
|
|
1110
|
+
function concat(a, b) {
|
|
1111
|
+
const result = new Uint8Array(a.length + b.length);
|
|
1112
|
+
result.set(a);
|
|
1113
|
+
result.set(b, a.length);
|
|
1114
|
+
return result;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1070
1117
|
//#endregion
|
|
1071
1118
|
//#region src/dom/network/fetch.ts
|
|
1072
1119
|
/**
|
|
@@ -1103,16 +1150,6 @@ async function fetchResolvable(addressable, options) {
|
|
|
1103
1150
|
return fetch(request);
|
|
1104
1151
|
}
|
|
1105
1152
|
/**
|
|
1106
|
-
* Fetch resolvable as bytes.
|
|
1107
|
-
*
|
|
1108
|
-
* Convenience wrapper around fetchResolvable that resolves the body as an
|
|
1109
|
-
* ArrayBuffer. Use this when you need the raw bytes (e.g. segment appends).
|
|
1110
|
-
* For text or streaming consumption, use fetchResolvable directly.
|
|
1111
|
-
*/
|
|
1112
|
-
async function fetchResolvableBytes(addressable, options) {
|
|
1113
|
-
return (await fetchResolvable(addressable, options)).arrayBuffer();
|
|
1114
|
-
}
|
|
1115
|
-
/**
|
|
1116
1153
|
* Extract text from Response.
|
|
1117
1154
|
*
|
|
1118
1155
|
* Accepts minimal Response-like object (just needs text() method).
|
|
@@ -1283,6 +1320,7 @@ function shouldResolve$1(state, event) {
|
|
|
1283
1320
|
*/
|
|
1284
1321
|
function syncPreloadAttribute(state, owners) {
|
|
1285
1322
|
return owners.subscribe((current) => {
|
|
1323
|
+
if (state.current.preload !== void 0) return;
|
|
1286
1324
|
const preload = current.mediaElement?.preload || void 0;
|
|
1287
1325
|
state.patch({ preload });
|
|
1288
1326
|
});
|
|
@@ -1411,14 +1449,6 @@ const SelectedTrackIdKeyByType = {
|
|
|
1411
1449
|
text: "selectedTextTrackId"
|
|
1412
1450
|
};
|
|
1413
1451
|
/**
|
|
1414
|
-
* Map track type to buffer owner property key.
|
|
1415
|
-
* Used for SourceBuffer references in owners.
|
|
1416
|
-
*/
|
|
1417
|
-
const BufferKeyByType = {
|
|
1418
|
-
video: "videoBuffer",
|
|
1419
|
-
audio: "audioBuffer"
|
|
1420
|
-
};
|
|
1421
|
-
/**
|
|
1422
1452
|
* Get selected track from state by type.
|
|
1423
1453
|
* Returns properly typed track (partially or fully resolved) or undefined.
|
|
1424
1454
|
* Type parameter T is inferred from the type argument.
|
|
@@ -1452,7 +1482,9 @@ function getSelectedTrack(state, type) {
|
|
|
1452
1482
|
* operation (if still needed) or preempts it.
|
|
1453
1483
|
*
|
|
1454
1484
|
* @param sourceBufferActor - Shared SourceBufferActor reference (not owned)
|
|
1455
|
-
* @param fetchBytes - Tracked fetch closure (owns throughput sampling)
|
|
1485
|
+
* @param fetchBytes - Tracked fetch closure (owns throughput sampling for segments).
|
|
1486
|
+
* Accepts an optional `minChunkSize` in options; init segments pass `Infinity`
|
|
1487
|
+
* so the entire body accumulates as one chunk before appending.
|
|
1456
1488
|
*/
|
|
1457
1489
|
function createSegmentLoaderActor(sourceBufferActor, fetchBytes) {
|
|
1458
1490
|
let pendingTasks = null;
|
|
@@ -1462,7 +1494,7 @@ function createSegmentLoaderActor(sourceBufferActor, fetchBytes) {
|
|
|
1462
1494
|
let running = false;
|
|
1463
1495
|
let destroyed = false;
|
|
1464
1496
|
const getBufferedSegments = (allSegments) => {
|
|
1465
|
-
const bufferedIds = new Set(sourceBufferActor.snapshot.context.segments.map((s) => s.id));
|
|
1497
|
+
const bufferedIds = new Set(sourceBufferActor.snapshot.context.segments.filter((s) => !s.partial).map((s) => s.id));
|
|
1466
1498
|
return allSegments.filter((s) => bufferedIds.has(s.id));
|
|
1467
1499
|
};
|
|
1468
1500
|
/**
|
|
@@ -1503,12 +1535,14 @@ function createSegmentLoaderActor(sourceBufferActor, fetchBytes) {
|
|
|
1503
1535
|
if (actorCtx.initTrackId !== track.id) tasks.push({
|
|
1504
1536
|
type: "append-init",
|
|
1505
1537
|
meta: { trackId: track.id },
|
|
1506
|
-
url: track.initialization.url
|
|
1538
|
+
url: track.initialization.url,
|
|
1539
|
+
...track.initialization.byteRange !== void 0 && { byteRange: track.initialization.byteRange }
|
|
1507
1540
|
});
|
|
1508
1541
|
if (range) {
|
|
1509
1542
|
const EPSILON = 1e-4;
|
|
1510
1543
|
const segmentsToLoad = getSegmentsToLoad(track.segments, bufferedSegments, currentTime).filter((seg) => {
|
|
1511
1544
|
const existing = actorCtx.segments.find((s) => Math.abs(s.startTime - seg.startTime) < EPSILON);
|
|
1545
|
+
if (existing?.partial) return true;
|
|
1512
1546
|
if (!existing?.trackBandwidth || !track.bandwidth) return true;
|
|
1513
1547
|
return track.bandwidth > existing.trackBandwidth;
|
|
1514
1548
|
});
|
|
@@ -1521,7 +1555,8 @@ function createSegmentLoaderActor(sourceBufferActor, fetchBytes) {
|
|
|
1521
1555
|
trackId: track.id,
|
|
1522
1556
|
trackBandwidth: track.bandwidth
|
|
1523
1557
|
},
|
|
1524
|
-
url: segment.url
|
|
1558
|
+
url: segment.url,
|
|
1559
|
+
...segment.byteRange !== void 0 && { byteRange: segment.byteRange }
|
|
1525
1560
|
});
|
|
1526
1561
|
}
|
|
1527
1562
|
return tasks;
|
|
@@ -1543,7 +1578,10 @@ function createSegmentLoaderActor(sourceBufferActor, fetchBytes) {
|
|
|
1543
1578
|
if (task.type === "append-init") {
|
|
1544
1579
|
inFlightInitTrackId = task.meta.trackId;
|
|
1545
1580
|
if (!signal.aborted) {
|
|
1546
|
-
const data = await fetchBytes(task, {
|
|
1581
|
+
const data = await fetchBytes(task, {
|
|
1582
|
+
signal,
|
|
1583
|
+
minChunkSize: Infinity
|
|
1584
|
+
});
|
|
1547
1585
|
const isTrackSwitch = pendingTasks?.some((t) => t.type === "append-init" && t.meta.trackId !== task.meta.trackId);
|
|
1548
1586
|
if (!signal.aborted || !isTrackSwitch) {
|
|
1549
1587
|
const appendSignal = signal.aborted ? new AbortController().signal : signal;
|
|
@@ -1558,10 +1596,10 @@ function createSegmentLoaderActor(sourceBufferActor, fetchBytes) {
|
|
|
1558
1596
|
}
|
|
1559
1597
|
inFlightSegmentId = task.meta.id;
|
|
1560
1598
|
if (!signal.aborted) {
|
|
1561
|
-
const
|
|
1599
|
+
const stream = await fetchBytes(task, { signal });
|
|
1562
1600
|
if (!signal.aborted) await sourceBufferActor.send({
|
|
1563
1601
|
type: "append-segment",
|
|
1564
|
-
data,
|
|
1602
|
+
data: stream,
|
|
1565
1603
|
meta: task.meta
|
|
1566
1604
|
}, signal);
|
|
1567
1605
|
}
|
|
@@ -1623,32 +1661,42 @@ function createSegmentLoaderActor(sourceBufferActor, fetchBytes) {
|
|
|
1623
1661
|
|
|
1624
1662
|
//#endregion
|
|
1625
1663
|
//#region src/dom/features/load-segments.ts
|
|
1626
|
-
const ActorKeyByType
|
|
1664
|
+
const ActorKeyByType = {
|
|
1627
1665
|
video: "videoBufferActor",
|
|
1628
1666
|
audio: "audioBufferActor"
|
|
1629
1667
|
};
|
|
1630
|
-
/**
|
|
1631
|
-
* Creates a fetch function that transparently samples bandwidth after each
|
|
1632
|
-
* completed request. Callers receive bytes; throughput tracking is invisible.
|
|
1633
|
-
*
|
|
1634
|
-
* `onSample` is an optional callback invoked after each sample is recorded,
|
|
1635
|
-
* used for bridging throughput state outward (e.g. migration bridge to global
|
|
1636
|
-
* state). A callback is used rather than a subscription so that no immediate
|
|
1637
|
-
* fire occurs at setup time — subscriptions fire on registration and would
|
|
1638
|
-
* trigger spurious state changes before any work has started.
|
|
1639
|
-
*/
|
|
1640
1668
|
function createTrackedFetch(throughput, onSample) {
|
|
1641
1669
|
return async (addressable, options) => {
|
|
1642
|
-
const
|
|
1643
|
-
const
|
|
1644
|
-
|
|
1645
|
-
const
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1670
|
+
const { minChunkSize,...fetchOptions } = options ?? {};
|
|
1671
|
+
const response = await fetchResolvable(addressable, fetchOptions);
|
|
1672
|
+
if (!response.body) throw new Error("Response has no body");
|
|
1673
|
+
const body = response.body;
|
|
1674
|
+
return { [Symbol.asyncIterator]: async function* () {
|
|
1675
|
+
let chunkStart = performance.now();
|
|
1676
|
+
for await (const chunk of new ChunkedStreamIterable(body, ...minChunkSize !== void 0 ? [{ minChunkSize }] : [])) {
|
|
1677
|
+
const elapsed = performance.now() - chunkStart;
|
|
1678
|
+
const next = sampleBandwidth(throughput.current, elapsed, chunk.byteLength);
|
|
1679
|
+
throughput.patch(next);
|
|
1680
|
+
throughput.flush();
|
|
1681
|
+
onSample?.(next);
|
|
1682
|
+
yield chunk;
|
|
1683
|
+
chunkStart = performance.now();
|
|
1684
|
+
}
|
|
1685
|
+
} };
|
|
1650
1686
|
};
|
|
1651
1687
|
}
|
|
1688
|
+
/**
|
|
1689
|
+
* Non-tracking fetch: eagerly starts the request and returns the response body
|
|
1690
|
+
* as a lazy chunk iterable. Used for audio tracks which don't sample bandwidth.
|
|
1691
|
+
* Pass `minChunkSize: Infinity` to accumulate the full body as a single chunk
|
|
1692
|
+
* (equivalent to arrayBuffer() but through the same streaming path).
|
|
1693
|
+
*/
|
|
1694
|
+
async function fetchStream(addressable, options) {
|
|
1695
|
+
const { minChunkSize,...fetchOptions } = options ?? {};
|
|
1696
|
+
const response = await fetchResolvable(addressable, fetchOptions);
|
|
1697
|
+
if (!response.body) throw new Error("Response has no body");
|
|
1698
|
+
return new ChunkedStreamIterable(response.body, ...minChunkSize !== void 0 ? [{ minChunkSize }] : []);
|
|
1699
|
+
}
|
|
1652
1700
|
function selectLoadingInputs([segmentsCanLoad, state], type) {
|
|
1653
1701
|
const { playbackInitiated, preload, currentTime } = state;
|
|
1654
1702
|
return {
|
|
@@ -1731,7 +1779,7 @@ function loadingInputsEq(prevState, curState) {
|
|
|
1731
1779
|
*/
|
|
1732
1780
|
function loadSegments({ state, owners }, config) {
|
|
1733
1781
|
const { type } = config;
|
|
1734
|
-
const actorKey = ActorKeyByType
|
|
1782
|
+
const actorKey = ActorKeyByType[type];
|
|
1735
1783
|
const initialBandwidth = state.current.bandwidthState;
|
|
1736
1784
|
const throughput = createState(initialBandwidth ?? {
|
|
1737
1785
|
fastEstimate: 0,
|
|
@@ -1743,7 +1791,7 @@ function loadSegments({ state, owners }, config) {
|
|
|
1743
1791
|
const fetchBytes = type === "video" ? createTrackedFetch(throughput, initialBandwidth !== void 0 ? (next) => {
|
|
1744
1792
|
state.patch({ bandwidthState: next });
|
|
1745
1793
|
state.flush();
|
|
1746
|
-
} : void 0) :
|
|
1794
|
+
} : void 0) : fetchStream;
|
|
1747
1795
|
const segmentLoader = createState(void 0);
|
|
1748
1796
|
const unsubActorLifecycle = owners.subscribe((o) => o[actorKey], (actor) => {
|
|
1749
1797
|
if (actor) segmentLoader.patch(createSegmentLoaderActor(actor, fetchBytes));
|
|
@@ -2080,25 +2128,30 @@ function trackPlaybackInitiated({ state, owners, events }) {
|
|
|
2080
2128
|
//#endregion
|
|
2081
2129
|
//#region src/dom/media/append-segment.ts
|
|
2082
2130
|
/**
|
|
2083
|
-
*
|
|
2131
|
+
* Append media data to a SourceBuffer.
|
|
2084
2132
|
*
|
|
2085
|
-
*
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
* Append a media segment to a SourceBuffer.
|
|
2089
|
-
*
|
|
2090
|
-
* Waits for the SourceBuffer to be ready (not updating), then appends
|
|
2091
|
-
* the segment data. Returns a promise that resolves when append completes.
|
|
2133
|
+
* Accepts either a full ArrayBuffer (single append) or an AsyncIterable of
|
|
2134
|
+
* Uint8Array chunks (one append per chunk, in order). Waits for `updateend`
|
|
2135
|
+
* between each call so appends are serialized correctly.
|
|
2092
2136
|
*
|
|
2093
|
-
*
|
|
2094
|
-
*
|
|
2095
|
-
* @returns Promise that resolves when append completes
|
|
2096
|
-
*
|
|
2097
|
-
* @example
|
|
2098
|
-
* const data = await fetch(segmentUrl).then(r => r.arrayBuffer());
|
|
2099
|
-
* await appendSegment(videoSourceBuffer, data);
|
|
2137
|
+
* Errors from the SourceBuffer (`error` event) or from the iterable are
|
|
2138
|
+
* propagated as rejections.
|
|
2100
2139
|
*/
|
|
2101
|
-
async function appendSegment(sourceBuffer,
|
|
2140
|
+
async function appendSegment(sourceBuffer, data, signal) {
|
|
2141
|
+
if (data instanceof ArrayBuffer) await appendChunk(sourceBuffer, data);
|
|
2142
|
+
else try {
|
|
2143
|
+
for await (const chunk of data) {
|
|
2144
|
+
if (signal?.aborted) throw signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
2145
|
+
await appendChunk(sourceBuffer, chunk);
|
|
2146
|
+
}
|
|
2147
|
+
} catch (e) {
|
|
2148
|
+
if (e instanceof DOMException && e.name === "AbortError" && !sourceBuffer.updating) try {
|
|
2149
|
+
sourceBuffer.abort();
|
|
2150
|
+
} catch {}
|
|
2151
|
+
throw e;
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
async function appendChunk(sourceBuffer, data) {
|
|
2102
2155
|
if (sourceBuffer.updating) await new Promise((resolve) => {
|
|
2103
2156
|
const onUpdateEnd = () => {
|
|
2104
2157
|
sourceBuffer.removeEventListener("updateend", onUpdateEnd);
|
|
@@ -2122,7 +2175,7 @@ async function appendSegment(sourceBuffer, segmentData) {
|
|
|
2122
2175
|
sourceBuffer.addEventListener("updateend", onUpdateEnd);
|
|
2123
2176
|
sourceBuffer.addEventListener("error", onError);
|
|
2124
2177
|
try {
|
|
2125
|
-
sourceBuffer.appendBuffer(
|
|
2178
|
+
sourceBuffer.appendBuffer(data);
|
|
2126
2179
|
} catch (error) {
|
|
2127
2180
|
cleanup();
|
|
2128
2181
|
reject(error);
|
|
@@ -2570,7 +2623,7 @@ function isLastSegmentAppended(segments, actor) {
|
|
|
2570
2623
|
if (segments.length === 0) return true;
|
|
2571
2624
|
const lastSeg = segments[segments.length - 1];
|
|
2572
2625
|
if (!lastSeg) return false;
|
|
2573
|
-
return actor?.snapshot.context.segments.some((s) => s.id === lastSeg.id) ?? false;
|
|
2626
|
+
return actor?.snapshot.context.segments.some((s) => s.id === lastSeg.id && !s.partial) ?? false;
|
|
2574
2627
|
}
|
|
2575
2628
|
/**
|
|
2576
2629
|
* Check if the last segment has been appended for each selected track.
|
|
@@ -2800,14 +2853,26 @@ function appendInitTask(message, { signal, getCtx, sourceBuffer }) {
|
|
|
2800
2853
|
};
|
|
2801
2854
|
}, { signal });
|
|
2802
2855
|
}
|
|
2803
|
-
function appendSegmentTask(message, { signal, getCtx, sourceBuffer }) {
|
|
2856
|
+
function appendSegmentTask(message, { signal, getCtx, sourceBuffer, onPartialContext }) {
|
|
2804
2857
|
return new Task(async (taskSignal) => {
|
|
2805
2858
|
const ctx = getCtx();
|
|
2806
2859
|
if (taskSignal.aborted) return ctx;
|
|
2807
|
-
await appendSegment(sourceBuffer, message.data);
|
|
2808
2860
|
const { meta } = message;
|
|
2809
2861
|
const EPSILON = 1e-4;
|
|
2810
2862
|
const filtered = ctx.segments.filter((s) => Math.abs(s.startTime - meta.startTime) >= EPSILON);
|
|
2863
|
+
if (!(message.data instanceof ArrayBuffer)) onPartialContext({
|
|
2864
|
+
...ctx,
|
|
2865
|
+
segments: [...filtered, {
|
|
2866
|
+
id: meta.id,
|
|
2867
|
+
startTime: meta.startTime,
|
|
2868
|
+
duration: meta.duration,
|
|
2869
|
+
trackId: meta.trackId,
|
|
2870
|
+
...meta.trackBandwidth !== void 0 && { trackBandwidth: meta.trackBandwidth },
|
|
2871
|
+
partial: true
|
|
2872
|
+
}],
|
|
2873
|
+
bufferedRanges: ctx.bufferedRanges
|
|
2874
|
+
});
|
|
2875
|
+
await appendSegment(sourceBuffer, message.data, taskSignal);
|
|
2811
2876
|
return {
|
|
2812
2877
|
...ctx,
|
|
2813
2878
|
segments: [...filtered, {
|
|
@@ -2882,10 +2947,18 @@ function createSourceBufferActor(sourceBuffer, initialContext) {
|
|
|
2882
2947
|
send(message, signal) {
|
|
2883
2948
|
if (state.current.status !== "idle") return Promise.reject(new SourceBufferActorError(`send() called while actor is ${state.current.status}`));
|
|
2884
2949
|
state.patch({ status: "updating" });
|
|
2950
|
+
const onPartialContext = (ctx) => {
|
|
2951
|
+
state.patch({
|
|
2952
|
+
status: "updating",
|
|
2953
|
+
context: ctx
|
|
2954
|
+
});
|
|
2955
|
+
state.flush();
|
|
2956
|
+
};
|
|
2885
2957
|
const task = messageToTask(message, {
|
|
2886
2958
|
signal,
|
|
2887
2959
|
getCtx: () => state.current.context,
|
|
2888
|
-
sourceBuffer
|
|
2960
|
+
sourceBuffer,
|
|
2961
|
+
onPartialContext
|
|
2889
2962
|
});
|
|
2890
2963
|
return runner.schedule(task).then(applyResult).catch(handleError);
|
|
2891
2964
|
},
|
|
@@ -2894,11 +2967,19 @@ function createSourceBufferActor(sourceBuffer, initialContext) {
|
|
|
2894
2967
|
if (messages.length === 0) return Promise.resolve();
|
|
2895
2968
|
state.patch({ status: "updating" });
|
|
2896
2969
|
let workingCtx = state.current.context;
|
|
2970
|
+
const onPartialContext = (ctx) => {
|
|
2971
|
+
state.patch({
|
|
2972
|
+
status: "updating",
|
|
2973
|
+
context: ctx
|
|
2974
|
+
});
|
|
2975
|
+
state.flush();
|
|
2976
|
+
};
|
|
2897
2977
|
for (const message of messages.slice(0, -1)) {
|
|
2898
2978
|
const task = messageToTask(message, {
|
|
2899
2979
|
signal,
|
|
2900
2980
|
getCtx: () => workingCtx,
|
|
2901
|
-
sourceBuffer
|
|
2981
|
+
sourceBuffer,
|
|
2982
|
+
onPartialContext
|
|
2902
2983
|
});
|
|
2903
2984
|
runner.schedule(task).then((newCtx) => {
|
|
2904
2985
|
workingCtx = newCtx;
|
|
@@ -2907,7 +2988,8 @@ function createSourceBufferActor(sourceBuffer, initialContext) {
|
|
|
2907
2988
|
const lastTask = messageToTask(messages[messages.length - 1], {
|
|
2908
2989
|
signal,
|
|
2909
2990
|
getCtx: () => workingCtx,
|
|
2910
|
-
sourceBuffer
|
|
2991
|
+
sourceBuffer,
|
|
2992
|
+
onPartialContext
|
|
2911
2993
|
});
|
|
2912
2994
|
return runner.schedule(lastTask).then(applyResult).catch(handleError);
|
|
2913
2995
|
},
|
|
@@ -2921,30 +3003,6 @@ function createSourceBufferActor(sourceBuffer, initialContext) {
|
|
|
2921
3003
|
|
|
2922
3004
|
//#endregion
|
|
2923
3005
|
//#region src/dom/features/setup-sourcebuffer.ts
|
|
2924
|
-
/** Map track type to SourceBufferActor owner property key. */
|
|
2925
|
-
const ActorKeyByType = {
|
|
2926
|
-
video: "videoBufferActor",
|
|
2927
|
-
audio: "audioBufferActor"
|
|
2928
|
-
};
|
|
2929
|
-
/**
|
|
2930
|
-
* Setup SourceBuffer task (module-level, pure).
|
|
2931
|
-
* Creates SourceBuffer for resolved track and waits a frame before completing.
|
|
2932
|
-
*/
|
|
2933
|
-
const setupSourceBufferTask = async ({ currentState, currentOwners }, context) => {
|
|
2934
|
-
const track = getSelectedTrack(currentState, context.config.type);
|
|
2935
|
-
if (!track || !isResolvedTrack(track)) return;
|
|
2936
|
-
if (!track.codecs || track.codecs.length === 0) return;
|
|
2937
|
-
const mimeCodec = buildMimeCodec(track);
|
|
2938
|
-
const buffer = createSourceBuffer(currentOwners.mediaSource, mimeCodec);
|
|
2939
|
-
const actor = createSourceBufferActor(buffer);
|
|
2940
|
-
const bufferKey = BufferKeyByType[context.config.type];
|
|
2941
|
-
const actorKey = ActorKeyByType[context.config.type];
|
|
2942
|
-
context.owners.patch({
|
|
2943
|
-
[bufferKey]: buffer,
|
|
2944
|
-
[actorKey]: actor
|
|
2945
|
-
});
|
|
2946
|
-
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
2947
|
-
};
|
|
2948
3006
|
/**
|
|
2949
3007
|
* Build MIME codec string from track metadata.
|
|
2950
3008
|
*
|
|
@@ -2960,66 +3018,47 @@ function buildMimeCodec(track) {
|
|
|
2960
3018
|
return `${track.mimeType}; codecs="${codecString}"`;
|
|
2961
3019
|
}
|
|
2962
3020
|
/**
|
|
2963
|
-
*
|
|
3021
|
+
* Setup all needed SourceBuffers as a single coordinated operation.
|
|
2964
3022
|
*
|
|
2965
|
-
*
|
|
2966
|
-
*
|
|
2967
|
-
*
|
|
3023
|
+
* Waits until ALL selected tracks (video and/or audio) are resolved with
|
|
3024
|
+
* codecs, then creates every SourceBuffer in one synchronous block before
|
|
3025
|
+
* patching owners. This guarantees that downstream consumers (e.g.
|
|
3026
|
+
* loadSegments) never see a partial set of SourceBuffers — preventing the
|
|
3027
|
+
* Firefox bug where appending to a video SourceBuffer before the audio
|
|
3028
|
+
* SourceBuffer exists causes mozHasAudio to be permanently false.
|
|
2968
3029
|
*
|
|
2969
|
-
*
|
|
2970
|
-
*
|
|
2971
|
-
* observations. Instead, setupMediaSource only patches owners.mediaSource after
|
|
2972
|
-
* it's already open, so if it exists in owners, it's ready to use.
|
|
3030
|
+
* Handles video-only, audio-only, and combined presentations correctly:
|
|
3031
|
+
* only the tracks that are actually selected are waited on and created.
|
|
2973
3032
|
*
|
|
2974
|
-
* Note: Track does not need to be resolved yet. The orchestration will wait
|
|
2975
|
-
* for the track to be resolved (via resolveTrack) before creating the SourceBuffer.
|
|
2976
|
-
*/
|
|
2977
|
-
function canSetupBuffer(state, owners, type) {
|
|
2978
|
-
if (!owners.mediaSource) return false;
|
|
2979
|
-
if (!getSelectedTrack(state, type)) return false;
|
|
2980
|
-
return true;
|
|
2981
|
-
}
|
|
2982
|
-
/**
|
|
2983
|
-
* Check if we should create SourceBuffer (not already created).
|
|
2984
|
-
*/
|
|
2985
|
-
function shouldSetupBuffer(owners, type) {
|
|
2986
|
-
const bufferKey = BufferKeyByType[type];
|
|
2987
|
-
return isUndefined(owners[bufferKey]);
|
|
2988
|
-
}
|
|
2989
|
-
/**
|
|
2990
|
-
* Setup SourceBuffer orchestration.
|
|
2991
|
-
*
|
|
2992
|
-
* Triggers when:
|
|
2993
|
-
* - MediaSource exists and is in 'open' state
|
|
2994
|
-
* - Track is selected (same condition as resolveTrack)
|
|
2995
|
-
*
|
|
2996
|
-
* Creates SourceBuffer when track becomes resolved with codecs.
|
|
2997
|
-
* This allows setupSourceBuffer to run in parallel with resolveTrack.
|
|
2998
|
-
*
|
|
2999
|
-
* Note: Text tracks don't use SourceBuffers and should be handled separately.
|
|
3000
|
-
*
|
|
3001
|
-
* Generic over track type - create one orchestration per track type:
|
|
3002
3033
|
* @example
|
|
3003
|
-
* const
|
|
3004
|
-
* const audioCleanup = setupSourceBuffer({ state, owners }, { type: 'audio' });
|
|
3034
|
+
* const cleanup = setupSourceBuffers({ state, owners });
|
|
3005
3035
|
*/
|
|
3006
|
-
function
|
|
3007
|
-
let
|
|
3036
|
+
function setupSourceBuffers({ state, owners }) {
|
|
3037
|
+
let setupDone = false;
|
|
3008
3038
|
return combineLatest([state, owners]).subscribe(async ([currentState, currentOwners]) => {
|
|
3009
|
-
if (
|
|
3010
|
-
if (!
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3039
|
+
if (setupDone) return;
|
|
3040
|
+
if (!currentOwners.mediaSource) return;
|
|
3041
|
+
const videoSelected = !!currentState.selectedVideoTrackId;
|
|
3042
|
+
const audioSelected = !!currentState.selectedAudioTrackId;
|
|
3043
|
+
if (!videoSelected && !audioSelected) return;
|
|
3044
|
+
const videoTrack = videoSelected ? getSelectedTrack(currentState, "video") : null;
|
|
3045
|
+
const audioTrack = audioSelected ? getSelectedTrack(currentState, "audio") : null;
|
|
3046
|
+
if (videoSelected && (!videoTrack || !isResolvedTrack(videoTrack) || !videoTrack.codecs?.length)) return;
|
|
3047
|
+
if (audioSelected && (!audioTrack || !isResolvedTrack(audioTrack) || !audioTrack.codecs?.length)) return;
|
|
3048
|
+
setupDone = true;
|
|
3049
|
+
const patch = {};
|
|
3050
|
+
if (videoSelected && videoTrack && isResolvedTrack(videoTrack)) {
|
|
3051
|
+
const buffer = createSourceBuffer(currentOwners.mediaSource, buildMimeCodec(videoTrack));
|
|
3052
|
+
patch.videoBuffer = buffer;
|
|
3053
|
+
patch.videoBufferActor = createSourceBufferActor(buffer);
|
|
3022
3054
|
}
|
|
3055
|
+
if (audioSelected && audioTrack && isResolvedTrack(audioTrack)) {
|
|
3056
|
+
const buffer = createSourceBuffer(currentOwners.mediaSource, buildMimeCodec(audioTrack));
|
|
3057
|
+
patch.audioBuffer = buffer;
|
|
3058
|
+
patch.audioBufferActor = createSourceBufferActor(buffer);
|
|
3059
|
+
}
|
|
3060
|
+
owners.patch(patch);
|
|
3061
|
+
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
3023
3062
|
});
|
|
3024
3063
|
}
|
|
3025
3064
|
|
|
@@ -3371,14 +3410,10 @@ function createPlaybackEngine(config = {}) {
|
|
|
3371
3410
|
state,
|
|
3372
3411
|
owners
|
|
3373
3412
|
}),
|
|
3374
|
-
|
|
3413
|
+
setupSourceBuffers({
|
|
3375
3414
|
state,
|
|
3376
3415
|
owners
|
|
3377
|
-
}
|
|
3378
|
-
setupSourceBuffer({
|
|
3379
|
-
state,
|
|
3380
|
-
owners
|
|
3381
|
-
}, { type: "audio" }),
|
|
3416
|
+
}),
|
|
3382
3417
|
trackCurrentTime({
|
|
3383
3418
|
state,
|
|
3384
3419
|
owners
|
|
@@ -3452,6 +3487,7 @@ function createPlaybackEngine(config = {}) {
|
|
|
3452
3487
|
var SpfMedia = class {
|
|
3453
3488
|
#engine;
|
|
3454
3489
|
#config;
|
|
3490
|
+
#preload = "";
|
|
3455
3491
|
/** Pending loadstart listener from a deferred play() retry, if any. */
|
|
3456
3492
|
#loadstartListener = null;
|
|
3457
3493
|
constructor(config = {}) {
|
|
@@ -3472,6 +3508,13 @@ var SpfMedia = class {
|
|
|
3472
3508
|
this.#cancelPendingPlay();
|
|
3473
3509
|
this.#engine.destroy();
|
|
3474
3510
|
}
|
|
3511
|
+
get preload() {
|
|
3512
|
+
return this.#preload;
|
|
3513
|
+
}
|
|
3514
|
+
set preload(value) {
|
|
3515
|
+
this.#preload = value;
|
|
3516
|
+
if (value) this.#engine.state.patch({ preload: value });
|
|
3517
|
+
}
|
|
3475
3518
|
get src() {
|
|
3476
3519
|
return this.#engine.state.current.presentation?.url ?? "";
|
|
3477
3520
|
}
|
|
@@ -3480,6 +3523,7 @@ var SpfMedia = class {
|
|
|
3480
3523
|
this.#cancelPendingPlay();
|
|
3481
3524
|
this.#engine.destroy();
|
|
3482
3525
|
this.#engine = createPlaybackEngine(this.#config);
|
|
3526
|
+
if (this.#preload) this.#engine.state.patch({ preload: this.#preload });
|
|
3483
3527
|
if (prevMediaElement) this.#engine.owners.patch({ mediaElement: prevMediaElement });
|
|
3484
3528
|
if (value) this.#engine.state.patch({ presentation: { url: value } });
|
|
3485
3529
|
}
|
|
@@ -3509,4 +3553,4 @@ var SpfMedia = class {
|
|
|
3509
3553
|
|
|
3510
3554
|
//#endregion
|
|
3511
3555
|
export { trackPlaybackInitiated as a, destroyVttParser as c, appendSegment as i, parseVttSegment as l, createPlaybackEngine as n, trackCurrentTime as o, flushBuffer as r, loadTextTrackCues as s, SpfMedia as t, loadSegments as u };
|
|
3512
|
-
//# sourceMappingURL=adapter-
|
|
3556
|
+
//# sourceMappingURL=adapter-CflgYzjF.js.map
|