@videojs/spf 10.0.0-beta.3 → 10.0.0-beta.5
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-CE86m9Eh.d.ts} +32 -4
- package/dist/adapter-CE86m9Eh.d.ts.map +1 -0
- package/dist/{adapter-CMw-rvbk.js → adapter-ClnRGbQf.js} +181 -154
- package/dist/adapter-ClnRGbQf.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
|
}
|
|
@@ -685,5 +713,5 @@ declare class SpfMedia {
|
|
|
685
713
|
play(): Promise<void>;
|
|
686
714
|
}
|
|
687
715
|
//#endregion
|
|
688
|
-
export { PresentationAction as a, SourceBufferActor as c,
|
|
689
|
-
//# sourceMappingURL=adapter-
|
|
716
|
+
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 };
|
|
717
|
+
//# sourceMappingURL=adapter-CE86m9Eh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-CE86m9Eh.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":";;AAsBA;;;;;ACHA;AAKA;AAKA;AAKA;AAWA;AAWA;;;;;;AAcA;;AAEiB,UDlDA,cAAA,CCkDA;EAA2B;EAAR,YAAA,EAAA,MAAA;EAAa;EAGb,eAAA,EAAA,MAAA;EAAd;EAGiB,YAAA,EAAA,MAAA;EAAG;EAAjB,eAAA,EAAA,MAAA;EAAgD;EAAjB,YAAA,EAAA,MAAA;;;;;ADxDxD;;;;cCZM,YAA2C,EAAA,OAAA,MAAA;AASjD;AAKA;AAKA;AAKiB,KAfL,aAeoB,CAAA,CAAA,CAAA,GAAA,CAAA,OAKP,EApBgB,CAoBf,EAAA,GAAA,IAAA;AAM1B;AAWA;;AAKoB,KArCR,aAqCQ,CAAA,CAAA,EAAA,CAAA,CAAA,GAAA,CAAA,KAAA,EArCsB,CAqCtB,EAAA,GArC4B,CAqC5B;;;;AASH,KAzCL,gBAyCkB,CAAA,CAAA,CAAA,GAAA,CAAA,OAAA,EAzCc,CAyCd,EAAA,GAAA,IAAA;;;;AAEM,UAtCnB,eAsCmB,CAAA,CAAA,CAAA,CAAA;EAAa;;;;EAMP,UAAA,CAAA,EAAA,CAAA,CAAA,EAvCvB,CAuCuB,EAAA,CAAA,EAvCjB,CAuCiB,EAAA,GAAA,OAAA;;;;;AAA6C,UAjCtE,WAiCsE,CAAA,CAAA,CAAA,CAAA;EAR7C;;AA4N1C;;EAAgE,UAAA,CAAA,EAAA,CAAA,CAAA,EAhP7C,CAgP6C,EAAA,CAAA,EAhPvC,CAgPuC,EAAA,GAAA,OAAA;;;;;UA1O/C;;YAEL,YAAA;EC1CK;EAOA,SAAA,OAAA,EDsCG,CCtCH;EA6BA;EAYL,SAAA,CAAA,QAAS,EDAC,aCAD,CDAe,CCAf,CAAA,CAAA,EAAA,GAAA,GAAA,IAAA;AAarB;AAeA;;;AAA8D,UDtB7C,aCsB6C,CAAA,CAAA,CAAA,SDtBpB,KCsBoB,CDtBd,CCsBc,CAAA,CAAA;EAAyC;EAA9C,KAAA,CAAA,OAAA,EDpBxC,CCoBwC,SAAA,MAAA,GDpBrB,OCoBqB,CDpBb,CCoBa,CAAA,GDpBR,CCoBQ,CAAA,EAAA,IAAA;EAAI;EA+BjD,SAAK,CAAA,QAAA,EDhDK,aCgDL,CDhDmB,CCgDnB,CAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAAG;EAClB,SAAA,CAAA,CAAA,CAAA,CAAA,QAAA,ED9CuB,aC8CvB,CD9CqC,CC8CrC,ED9CwC,CC8CxC,CAAA,EAAA,QAAA,ED9CsD,gBC8CtD,CD9CuE,CC8CvE,CAAA,EAAA,OAAA,CAAA,ED9CqF,eC8CrF,CD9CqG,CC8CrG,CAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EACA;EACQ,KAAA,EAAA,EAAA,IAAA;;;;AAYV;;;;;;;AAcA;;;;;;AAcA;AA6CA;;;;;;;;;AAgCA;;;;;;;;AAQA;AAKA;AAKA;AAMA;AAA2B,iBDuBX,WCvBW,CAAA,CAAA,CAAA,CAAA,OAAA,EDuBa,CCvBb,EAAA,MAAA,CAAA,EDuByB,WCvBzB,CDuBqC,CCvBrC,CAAA,CAAA,EDuB0C,aCvB1C,CDuBwD,CCvBxD,CAAA;;;;AFrP3B;;;;;ACHA;AAKA;AAKA;AAKA;AAWA;AAWiB,UCxCA,GAAA,CDwCK;EAEV,EAAA,EAAA,MAAA;;;;;AAYK,UC/CA,iBAAA,CD+Ca;EAAkB,GAAA,EAAA,MAAA;EAE/B,SAAA,CAAA,EAAA;IAA2B,KAAA,EAAA,MAAA;IAAR,GAAA,EAAA,MAAA;EAAa,CAAA;;;;AA0NjD;;AAAgE,UC9O/C,QAAA,CD8O+C;EAAZ,SAAA,EAAA,MAAA;EAA+B,QAAA,EAAA,MAAA;;;;;KClOvE,SAAA;AAhDZ;AAOA;AA6BA;AAYA;AAaA;AAeA;;AAAgD,UAf/B,SAAA,CAe+B;EAAc,kBAAA,EAAA,MAAA;EAAyC,oBAAA,CAAA,EAAA,MAAA;;;AA+BvG;;;;;AAQqB,KAvCT,iBAuCS,CAAA,UAvCmB,KAuCnB,GAvC2B,KAuC3B,CAAA,GAvCoC,IAuCpC,CAvCyC,CAuCzC,EAAA,UAAA,GAAA,gBAAA,GAAA,MAvCkF,QAuClF,CAAA,GAAA;EACP,QAAA,CAAA,EAAA,KAAA;EAAO,QAAA,CAAA,EAAA,KAAA;EAMT,SAAA,CAAA,EAAA,KAAU;EAAG,cAAA,CAAA,EAAA,KAAA;CACT;AA2BhB;AA6CA;;;;;;;AAEkC,KA1FtB,KAAA,GAAQ,GA0Fc,GAzFhC,iBAyFgC,GAxFhC,QAwFgC,GAAA;EAAC,IAAA,EAvFzB,SAuFyB;EA8BvB,MAAA,CAAA,EAAA,MAAA,EAAc;EAAW,QAAA,EAAA,MAAA;EAAQ,QAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EAAS,SAAA,EAAA,MAAA;EAC9C,cAAA,CAAA,EAjHa,iBAiHb;EACwB,QAAA,EAjHlB,OAiHkB,EAAA;CAAf;;AAMjB;AAKA;AAKY,KA3HA,UAAA,GAAa,KA2HG,GA1H1B,QA0H4C,CA1HnC,IA0HoB,CA1Hf,KA0He,EAAA,gBAAc,GAAA,QAAA,CAAA,CAAA,GAAA;EAMjC,IAAA,EAAA,OAAA;EAAe,KAAA,CAAA,EAAA,MAAA;EAAoB,MAAA,CAAA,EAAA,MAAA;EAAoB,SAAA,CAAA,EA1HnD,SA0HmD;EAAgB,YAAA,CAAA,EAAA,MAAA;AAUnF,CAAA;;;;AAAwD,KA7H5C,UAAA,GAAa,KA6H+B,GA5HtD,QA4HsD,CA5H7C,IA4H6C,CA5HxC,KA4HwC,EAAA,gBAAA,GAAA,QAAA,CAAA,CAAA,GAAA;EA+B5C,IAAA,EAAA,OAAA;EAAe,OAAA,EAAA,MAAA;EACzB,IAAA,EAAA,MAAA;EACQ,UAAA,EAAA,MAAA;EAAR,QAAA,EAAA,MAAA;EACiB,OAAA,CAAA,EAAA,OAAA;EAAY,UAAA,CAAA,EAAA,OAAA;;;;ACvS/B;KDsJY,SAAA,GAAY;;;EE5JP,KAAA,EAAA,MAAA;EAMA,IAAA,EAAA,WAAK,GAAA,UAAA;EAEa,OAAA,CAAA,EAAA,OAAA;EAAQ,UAAA,CAAA,EAAA,OAAA;EAAtB,MAAA,CAAA,EAAA,OAAA;CAQ0B;;;;;AEf/C;AAKA;;;;;AAQA;AACA;AACA;AACY,KJwLA,cIxLmB,CAAA,UJwLM,KIxLN,GJwLc,KIxLd,CAAA,GJwLuB,GIxLvB,GAAA;EAAG,IAAA,EJyL1B,CIzL0B,CAAA,MAAA,CAAA;EAAoB,MAAA,EAAA,CJ0L3C,iBI1L2C,CJ0LzB,CI1LyB,CAAA,GJ0LpB,CI1LoB,CAAA,EAAA;CAAuB;;;;;;;ACmF5D,KLqIL,cKrIK,CAAA,ULqIoB,KKpIzB,GLoIiC,KKpI5B,CAAA,GLoIqC,GKpIrC,GAAA;EASL,IAAA,EL4HJ,CK5HI,CAAA,MAAA,CAAA;EAKK,aAAA,ELwHA,cKxHwB,CLwHT,CKxHS,CAAA,EAAA;AAYzC,CAAA;AAqGA;;;AAIuB,KLSX,iBAAA,GAAoB,cKTT,CLSwB,UKTxB,CAAA;;;;AACA,KLaX,iBAAA,GAAoB,cKbT,CLawB,UKbxB,CAAA;;;;AC5OjB,KN8PM,gBAAA,GAAmB,cM9P4B,CN8Pb,SM9Pa,CAAA;AAK3D;;;;AAAoE,KN+PxD,YAAA,GAAe,iBM/PyC,GN+PrB,iBM/PqB,GN+PD,gBM/PC;AAKpE;;;;AAEkB,KNkQN,OAAA,GAAU,GMlQJ,GNkQU,iBMlQV,GNkQ8B,QMlQ9B;;;;AEsDlB;;;;ACzCY,KToRA,YAAA,GAAe,GSpRK,GTqR9B,iBSrR8B,GTsR9B,OStR8B,CTsRtB,QStRsB,CAAA,GAAA;iBTuRb;;;;AFjSnB;;;;ACZM,UEMW,mBAAA,CFNgC;EASrC,YAAA,CAAA,EEFK,iBFEyB,GEFL,YFEK,GAAA,SAAA;EAK9B,oBAAa,CAAA,EAAA,MAAA,GAAiB,SAAO;EAKrC,oBAAgB,CAAA,EAAA,MAAA,GAAgB,SAAC;EAK5B,mBAAe,CAAA,EAAA,MAAA,GAKb,SAAO;AAM1B;;;;ADvBA;;;;;ACHA;AAKA;AAKA;AAKiB,UGxBA,aHwBe,CAAA,eAKN,MAAA,EAAA,OAAA,CAAA,CAAA;EAMT,MAAA,EGlCP,MHkCkB;EAWX,OAAA,EG5CN,OH4CW;;;AAQc,UGhDnB,KHgDmB,CAAA,eAAA,MAAA,EAAA,OAAA,CAAA,CAAA;EAAd;EAAa,SAAA,QAAA,EG9Cd,aH8Cc,CG9CA,MH8CA,EG9CQ,OH8CR,CAAA;EAMlB;;;;;;EAKmB,SAAA,CAAA,QAAA,EAAA,CAAA,QAAA,EGjDH,aHiDG,CGjDW,MHiDX,EGjDmB,OHiDnB,CAAA,EAAA,GAAA,IAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAAd;EAGiB,OAAA,EAAA,EAAA,IAAA;;;;;ADxDvC;;;;;ACHA;AAKA;AAKY,KIpBA,UAAA,GAAa,WJoBmB,GIpBL,aJoBM,CIpBQ,UJoBR,CAAA;AAK7C;AAWA;AAWA;;;;;;AAcA;;AAEiB,iBInDK,aAAA,CJmDL,YAAA,EInDiC,YJmDjC,EAAA,IAAA,EInDqD,UJmDrD,EAAA,MAAA,CAAA,EInD0E,WJmD1E,CAAA,EInDwF,OJmDxF,CAAA,IAAA,CAAA;;;UK7DA,aAAA;;ELDX,GAAA,EAAA,MAAA;AASN;AAKY,KKRA,iBAAA,GAAoB,ILQU,CKRL,OLQY,EAAA,IAAA,GAAA,WAAA,GAAA,UAAA,CAAA,GAAA;EAKrC,OAAA,EKZD,KLYC,CAAA,IAAgB,CAAA;EAKX;EAWA,cAAW,CAAA,EAAA,MAAA;AAW5B,CAAA;AAKoB,KKrCR,iBAAA,GLqCQ;EAGgB,IAAA,EAAA,aAAA;EAAd,IAAA,EKxCuC,ULwCvC;EAAa,IAAA,EAAA;IAMlB,OAAA,EK9CyE,KL8C5D,CAAA,IAAA,CAAA;EAAkB,CAAA;CAE/B;AAA2B,KK/ChC,oBAAA,GL+CgC;EAAR,IAAA,EAAA,gBAAA;EAAa,IAAA,EK/CkB,UL+ClB;EAGb,IAAA,EKlDiD,iBLkDjD;CAAd;AAGiB,KKpD3B,aAAA,GLoD2B;EAAG,IAAA,EAAA,QAAA;EAAjB,KAAA,EAAA,MAAA;EAAgD,GAAA,EAAA,MAAA;CAAjB;AAA+C,KKnD3F,mBAAA,GAAsB,iBLmDqE,GKnDjD,oBLmDiD,GKnD1B,aLmD0B;;AAR7D,KKxC9B,uBAAA,GLwC8B,MAAA,GAAA,UAAA,GAAA,WAAA;;AA4N1B,UKjQC,wBAAA,CLiQU;EAAa,WAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EAAwB,QAAA,EK/PpD,KL+PoD,CK9P5D,IL8P4D,CK9PvD,OL8PuD,EAAA,IAAA,GAAA,WAAA,GAAA,UAAA,CAAA,GAAA;IAAZ,OAAA,EK7PrC,KL6PqC,CAAA,IAAA,CAAA;IAA+B,cAAA,CAAA,EAAA,MAAA;IAAd;;;;;IClRpD,OAAG,CAAA,EAAA,OAAA;EAOH,CAAA,CAAA;EA6BA,cAAQ,EILP,aJKO,EAAA;AAYzB;;AA4DE,UI3De,iBAAA,SAA0B,KJ2DzC,CI3D+C,uBJ2D/C,EI3DwE,wBJ2DxE,CAAA,CAAA;EACA,IAAA,CAAA,OAAA,EI3Dc,mBJ2Dd,EAAA,MAAA,EI3D2C,WJ2D3C,CAAA,EI3DyD,OJ2DzD,CAAA,IAAA,CAAA;EACQ,KAAA,CAAA,QAAA,EI3DQ,mBJ2DR,EAAA,EAAA,MAAA,EI3DuC,WJ2DvC,CAAA,EI3DqD,OJ2DrD,CAAA,IAAA,CAAA;;;;;;;ADpHJ,UMoGW,qBAAA,CNpGgC;EASrC,QAAA,EM4FA,KN5FA,CAAa;IAKb,EAAA,EAAA,MAAA;EAKA,CAAA,CAAA;AAKZ;AAWA;AAWA;;;;;AAQmC,KMwDvB,oBAAA,GAAuB,MNxDA,CAAA,MAAA,EMwDe,qBNxDf,CAAA;AAMnC;;;AAE4C,UMqD3B,wBAAA,CNrD2B;EAAR,mBAAA,CAAA,EAAA,MAAA;EAAa,YAAA,CAAA,EMuDhC,YNvDgC;EAGb;EAAd,WAAA,CAAA,EAAA,MAAA;EAGiB;EAAG,eAAA,CAAA,EMqDtB,oBNrDsB;;;;;AAA6C,UM2DtE,yBAAA,CN3DsE;EAR7C,UAAA,CAAA,EMoE3B,GNpE2B,CAAA,MAAA,EMoEf,gBNpEe,CAAA;;;;;;ACqD1C;;;;;;;;AAeA;;;AACW,iBKmGK,iBAAA,CLnGL;EAAA,KAAA;EAAA;CAAA,EAAA;EAAT,KAAA,EKuGO,aLvGP,CKuGqB,wBLvGrB,CAAA;EAMc,MAAA,EKkGN,aLlGM,CKkGQ,yBLlGR,CAAA;CAAS,CAAA,EAAA,GAAA,GAAA,IAAA;;;;AF3HzB;;;;;ACHA,cOZM,mBPYmC,EAAC,OAAA,MAAA;AAK1C;AAKA;AAKA;AAWiB,KOjCL,aPiCgB,CAAA,UOjCQ,IPsCV,COtCe,KPsCf,EAAA,MAAA,CAAA,CAAA,GAAA,CAAA,KAAA,EOtCyC,CPsCzC,EAAA,GAAA,IAAA;AAM1B;;;AAQoC,UO/CnB,WP+CmB,CAAA,UO/CG,IP+CH,CO/CQ,KP+CR,EAAA,MAAA,CAAA,GAAA;EAAd,IAAA,EAAA,MAAA;CAAa,CAAA,CAAA;EAMlB,COpDd,mBAAA,CPoD2B,EAAA,IAAA;EAAkB,QAAA,CAAA,KAAA,EOnD9B,CPmD8B,CAAA,EAAA,IAAA;EAE/B,SAAA,CAAA,QAAA,EOpDK,aPoDL,COpDmB,CPoDnB,CAAA,CAAA,EAAA,GAAA,GAAA,IAAA;;;;;;;;;;;;;;;AA0NjB;;;;;;;;;iBOrPgB,4BAA4B,KAAK,mBAAmB,YAAY;;;;;;;AN+CnB,KOJjD,kBAAA,GPIiD;EA+BjD,IAAA,EAAA,MAAK;CAAG,GAAA;EAClB,IAAA,EAAA,OAAA;CACA,GAAA;EACQ,IAAA,EAAA,MAAA;EAKW,GAAA,EAAA,MAAA;CACP;;;;;;;AD8JE,KSzNJ,qBAAA,GTyNe;EAAa,IAAA,EAAA,MAAA;CAAwB,GAAA;EAAZ,IAAA,EAAA,OAAA;CAA+B;;;;;;;AApNzC,KU9C9B,oBAAA,GV8C8B;EAAjB,IAAA,EAAA,qBAAA;CAAgD;;;AAjDzE;AAKA;AAWA;AAWA;AAEY,KWtBA,oBAAA,GACR,kBXqBQ,GWpBR,qBXoBQ,GWnBR,oBXmBQ,GAAA;EAGQ,IAAA,EAAA,gBAAA;CAGgB;;;AAMpC;AAAgD,UWzB/B,oBAAA,CXyB+B;EAE/B;;;;EAGmB,gBAAA,CAAA,EAAA,MAAA;EAAd;;;;EAGmD,sBAAA,CAAA,EAAA,MAAA;EAAjB;;;;EART,yBAAA,CAAA,EAAA,MAAA;EA4N/B;;;;EAAmE,mBAAA,CAAA,EAAA,OAAA;EAAd;;;;;AClRrE;AAOA;AA6BA;AAYA;AAaA;AAeY,UUXK,mBAAA,CVWY;EAAW,YAAA,CAAA,EAAA,GAAA;EAAQ,OAAA,CAAA,EAAA,MAAA;EAAc,oBAAA,CAAA,EAAA,MAAA;EAAyC,oBAAA,CAAA,EAAA,MAAA;EAA9C,mBAAA,CAAA,EAAA,MAAA;EAAI,cAAA,CAAA,EUC1C,cVD0C;EA+BjD,WAAK,CAAA,EAAA,OAAA;EAAG,eAAA,CAAA,EUtBA,oBVsBA;EAClB,WAAA,CAAA,EAAA,MAAA;EACA,iBAAA,CAAA,EAAA,OAAA;;;;;AAaF;AAAyB,UUxBR,oBAAA,CVwBQ;EACT,YAAA,CAAA,EUvBC,gBVuBD,GAAA,SAAA;EAAL,WAAA,CAAA,EUpBK,WVoBL;EAAT,WAAA,CAAA,EUjBc,YViBd;EAMc,WAAA,CAAA,EUtBA,YVsBA;EAAS,gBAAA,CAAA,EUrBJ,iBVqBI;EAOb,gBAAU,CAAA,EU3BD,iBV2BC;EAAG,UAAA,CAAA,EUxBV,GVwBU,CAAA,MAAA,EUxBE,gBVwBF,CAAA;;;;;AAcb,UUhCK,cAAA,CVgCO;EA6CZ;;;EAA0C,KAAA,EUzE7C,UVyE6C,CAAA,OUzE3B,WVyE2B,CUzEf,mBVyEe,CAAA,CAAA;EAC9C;;;EAC0B,MAAA,EUtExB,UVsEwB,CAAA,OUtEN,WVsEM,CUtEM,oBVsEN,CAAA,CAAA;EAAC;AA8BnC;;EAA6C,MAAA,EU/FnC,UV+FmC,CAAA,OU/FjB,iBV+FiB,CU/FC,oBV+FD,CAAA,CAAA;EAAS;;;EAErC,OAAA,EAAA,GAAA,GAAA,IAAA;;AAMjB;AAKA;AAKA;AAMA;;;;;AAUA;;;;;AA+BA;;;;;;;;;;ACpSA;;;;ACNA;AAMA;;;;;;AAUiC,iBQoKjB,oBAAA,CRpKiB,MAAA,CAAA,EQoKY,oBRpKZ,CAAA,EQoKwC,cRpKxC;;;;;;;AHPjC;AAKA;AAKA;AAKA;AAWA;AAWA;;;;;;AAcA;;;;;;;AAKsB,cYlDT,QAAA,CZkDS;EAGiB,CAAA,OAAA;EAAG,WAAA,CAAA,MAAA,CAAA,EY9CpB,oBZ8CoB;EAAjB,IAAA,MAAA,CAAA,CAAA,EYzCT,cZyCS;EAAgD,MAAA,CAAA,YAAA,EYjClD,gBZiCkD,CAAA,EAAA,IAAA;EAAjB,MAAA,CAAA,CAAA,EAAA,IAAA;EAA+C,OAAA,CAAA,CAAA,EAAA,IAAA;EAAhB,IAAA,GAAA,CAAA,CAAA,EAAA,MAAA;EAR7C,IAAA,GAAA,CAAA,KAAA,EAAA,MAAA;EAAK,IAAA,CAAA,CAAA,EYoBrC,OZpBqC,CAAA,IAAA,CAAA;AA4N/C"}
|
|
@@ -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).
|
|
@@ -1411,14 +1448,6 @@ const SelectedTrackIdKeyByType = {
|
|
|
1411
1448
|
text: "selectedTextTrackId"
|
|
1412
1449
|
};
|
|
1413
1450
|
/**
|
|
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
1451
|
* Get selected track from state by type.
|
|
1423
1452
|
* Returns properly typed track (partially or fully resolved) or undefined.
|
|
1424
1453
|
* Type parameter T is inferred from the type argument.
|
|
@@ -1452,7 +1481,9 @@ function getSelectedTrack(state, type) {
|
|
|
1452
1481
|
* operation (if still needed) or preempts it.
|
|
1453
1482
|
*
|
|
1454
1483
|
* @param sourceBufferActor - Shared SourceBufferActor reference (not owned)
|
|
1455
|
-
* @param fetchBytes - Tracked fetch closure (owns throughput sampling)
|
|
1484
|
+
* @param fetchBytes - Tracked fetch closure (owns throughput sampling for segments).
|
|
1485
|
+
* Accepts an optional `minChunkSize` in options; init segments pass `Infinity`
|
|
1486
|
+
* so the entire body accumulates as one chunk before appending.
|
|
1456
1487
|
*/
|
|
1457
1488
|
function createSegmentLoaderActor(sourceBufferActor, fetchBytes) {
|
|
1458
1489
|
let pendingTasks = null;
|
|
@@ -1462,7 +1493,7 @@ function createSegmentLoaderActor(sourceBufferActor, fetchBytes) {
|
|
|
1462
1493
|
let running = false;
|
|
1463
1494
|
let destroyed = false;
|
|
1464
1495
|
const getBufferedSegments = (allSegments) => {
|
|
1465
|
-
const bufferedIds = new Set(sourceBufferActor.snapshot.context.segments.map((s) => s.id));
|
|
1496
|
+
const bufferedIds = new Set(sourceBufferActor.snapshot.context.segments.filter((s) => !s.partial).map((s) => s.id));
|
|
1466
1497
|
return allSegments.filter((s) => bufferedIds.has(s.id));
|
|
1467
1498
|
};
|
|
1468
1499
|
/**
|
|
@@ -1503,12 +1534,14 @@ function createSegmentLoaderActor(sourceBufferActor, fetchBytes) {
|
|
|
1503
1534
|
if (actorCtx.initTrackId !== track.id) tasks.push({
|
|
1504
1535
|
type: "append-init",
|
|
1505
1536
|
meta: { trackId: track.id },
|
|
1506
|
-
url: track.initialization.url
|
|
1537
|
+
url: track.initialization.url,
|
|
1538
|
+
...track.initialization.byteRange !== void 0 && { byteRange: track.initialization.byteRange }
|
|
1507
1539
|
});
|
|
1508
1540
|
if (range) {
|
|
1509
1541
|
const EPSILON = 1e-4;
|
|
1510
1542
|
const segmentsToLoad = getSegmentsToLoad(track.segments, bufferedSegments, currentTime).filter((seg) => {
|
|
1511
1543
|
const existing = actorCtx.segments.find((s) => Math.abs(s.startTime - seg.startTime) < EPSILON);
|
|
1544
|
+
if (existing?.partial) return true;
|
|
1512
1545
|
if (!existing?.trackBandwidth || !track.bandwidth) return true;
|
|
1513
1546
|
return track.bandwidth > existing.trackBandwidth;
|
|
1514
1547
|
});
|
|
@@ -1521,7 +1554,8 @@ function createSegmentLoaderActor(sourceBufferActor, fetchBytes) {
|
|
|
1521
1554
|
trackId: track.id,
|
|
1522
1555
|
trackBandwidth: track.bandwidth
|
|
1523
1556
|
},
|
|
1524
|
-
url: segment.url
|
|
1557
|
+
url: segment.url,
|
|
1558
|
+
...segment.byteRange !== void 0 && { byteRange: segment.byteRange }
|
|
1525
1559
|
});
|
|
1526
1560
|
}
|
|
1527
1561
|
return tasks;
|
|
@@ -1543,7 +1577,10 @@ function createSegmentLoaderActor(sourceBufferActor, fetchBytes) {
|
|
|
1543
1577
|
if (task.type === "append-init") {
|
|
1544
1578
|
inFlightInitTrackId = task.meta.trackId;
|
|
1545
1579
|
if (!signal.aborted) {
|
|
1546
|
-
const data = await fetchBytes(task, {
|
|
1580
|
+
const data = await fetchBytes(task, {
|
|
1581
|
+
signal,
|
|
1582
|
+
minChunkSize: Infinity
|
|
1583
|
+
});
|
|
1547
1584
|
const isTrackSwitch = pendingTasks?.some((t) => t.type === "append-init" && t.meta.trackId !== task.meta.trackId);
|
|
1548
1585
|
if (!signal.aborted || !isTrackSwitch) {
|
|
1549
1586
|
const appendSignal = signal.aborted ? new AbortController().signal : signal;
|
|
@@ -1558,10 +1595,10 @@ function createSegmentLoaderActor(sourceBufferActor, fetchBytes) {
|
|
|
1558
1595
|
}
|
|
1559
1596
|
inFlightSegmentId = task.meta.id;
|
|
1560
1597
|
if (!signal.aborted) {
|
|
1561
|
-
const
|
|
1598
|
+
const stream = await fetchBytes(task, { signal });
|
|
1562
1599
|
if (!signal.aborted) await sourceBufferActor.send({
|
|
1563
1600
|
type: "append-segment",
|
|
1564
|
-
data,
|
|
1601
|
+
data: stream,
|
|
1565
1602
|
meta: task.meta
|
|
1566
1603
|
}, signal);
|
|
1567
1604
|
}
|
|
@@ -1623,32 +1660,42 @@ function createSegmentLoaderActor(sourceBufferActor, fetchBytes) {
|
|
|
1623
1660
|
|
|
1624
1661
|
//#endregion
|
|
1625
1662
|
//#region src/dom/features/load-segments.ts
|
|
1626
|
-
const ActorKeyByType
|
|
1663
|
+
const ActorKeyByType = {
|
|
1627
1664
|
video: "videoBufferActor",
|
|
1628
1665
|
audio: "audioBufferActor"
|
|
1629
1666
|
};
|
|
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
1667
|
function createTrackedFetch(throughput, onSample) {
|
|
1641
1668
|
return async (addressable, options) => {
|
|
1642
|
-
const
|
|
1643
|
-
const
|
|
1644
|
-
|
|
1645
|
-
const
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1669
|
+
const { minChunkSize,...fetchOptions } = options ?? {};
|
|
1670
|
+
const response = await fetchResolvable(addressable, fetchOptions);
|
|
1671
|
+
if (!response.body) throw new Error("Response has no body");
|
|
1672
|
+
const body = response.body;
|
|
1673
|
+
return { [Symbol.asyncIterator]: async function* () {
|
|
1674
|
+
let chunkStart = performance.now();
|
|
1675
|
+
for await (const chunk of new ChunkedStreamIterable(body, ...minChunkSize !== void 0 ? [{ minChunkSize }] : [])) {
|
|
1676
|
+
const elapsed = performance.now() - chunkStart;
|
|
1677
|
+
const next = sampleBandwidth(throughput.current, elapsed, chunk.byteLength);
|
|
1678
|
+
throughput.patch(next);
|
|
1679
|
+
throughput.flush();
|
|
1680
|
+
onSample?.(next);
|
|
1681
|
+
yield chunk;
|
|
1682
|
+
chunkStart = performance.now();
|
|
1683
|
+
}
|
|
1684
|
+
} };
|
|
1650
1685
|
};
|
|
1651
1686
|
}
|
|
1687
|
+
/**
|
|
1688
|
+
* Non-tracking fetch: eagerly starts the request and returns the response body
|
|
1689
|
+
* as a lazy chunk iterable. Used for audio tracks which don't sample bandwidth.
|
|
1690
|
+
* Pass `minChunkSize: Infinity` to accumulate the full body as a single chunk
|
|
1691
|
+
* (equivalent to arrayBuffer() but through the same streaming path).
|
|
1692
|
+
*/
|
|
1693
|
+
async function fetchStream(addressable, options) {
|
|
1694
|
+
const { minChunkSize,...fetchOptions } = options ?? {};
|
|
1695
|
+
const response = await fetchResolvable(addressable, fetchOptions);
|
|
1696
|
+
if (!response.body) throw new Error("Response has no body");
|
|
1697
|
+
return new ChunkedStreamIterable(response.body, ...minChunkSize !== void 0 ? [{ minChunkSize }] : []);
|
|
1698
|
+
}
|
|
1652
1699
|
function selectLoadingInputs([segmentsCanLoad, state], type) {
|
|
1653
1700
|
const { playbackInitiated, preload, currentTime } = state;
|
|
1654
1701
|
return {
|
|
@@ -1731,7 +1778,7 @@ function loadingInputsEq(prevState, curState) {
|
|
|
1731
1778
|
*/
|
|
1732
1779
|
function loadSegments({ state, owners }, config) {
|
|
1733
1780
|
const { type } = config;
|
|
1734
|
-
const actorKey = ActorKeyByType
|
|
1781
|
+
const actorKey = ActorKeyByType[type];
|
|
1735
1782
|
const initialBandwidth = state.current.bandwidthState;
|
|
1736
1783
|
const throughput = createState(initialBandwidth ?? {
|
|
1737
1784
|
fastEstimate: 0,
|
|
@@ -1743,7 +1790,7 @@ function loadSegments({ state, owners }, config) {
|
|
|
1743
1790
|
const fetchBytes = type === "video" ? createTrackedFetch(throughput, initialBandwidth !== void 0 ? (next) => {
|
|
1744
1791
|
state.patch({ bandwidthState: next });
|
|
1745
1792
|
state.flush();
|
|
1746
|
-
} : void 0) :
|
|
1793
|
+
} : void 0) : fetchStream;
|
|
1747
1794
|
const segmentLoader = createState(void 0);
|
|
1748
1795
|
const unsubActorLifecycle = owners.subscribe((o) => o[actorKey], (actor) => {
|
|
1749
1796
|
if (actor) segmentLoader.patch(createSegmentLoaderActor(actor, fetchBytes));
|
|
@@ -2080,25 +2127,23 @@ function trackPlaybackInitiated({ state, owners, events }) {
|
|
|
2080
2127
|
//#endregion
|
|
2081
2128
|
//#region src/dom/media/append-segment.ts
|
|
2082
2129
|
/**
|
|
2083
|
-
*
|
|
2084
|
-
*
|
|
2085
|
-
* Appends media segments (ArrayBuffer) to SourceBuffer.
|
|
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.
|
|
2130
|
+
* Append media data to a SourceBuffer.
|
|
2092
2131
|
*
|
|
2093
|
-
*
|
|
2094
|
-
*
|
|
2095
|
-
*
|
|
2132
|
+
* Accepts either a full ArrayBuffer (single append) or an AsyncIterable of
|
|
2133
|
+
* Uint8Array chunks (one append per chunk, in order). Waits for `updateend`
|
|
2134
|
+
* between each call so appends are serialized correctly.
|
|
2096
2135
|
*
|
|
2097
|
-
*
|
|
2098
|
-
*
|
|
2099
|
-
* await appendSegment(videoSourceBuffer, data);
|
|
2136
|
+
* Errors from the SourceBuffer (`error` event) or from the iterable are
|
|
2137
|
+
* propagated as rejections.
|
|
2100
2138
|
*/
|
|
2101
|
-
async function appendSegment(sourceBuffer,
|
|
2139
|
+
async function appendSegment(sourceBuffer, data, signal) {
|
|
2140
|
+
if (data instanceof ArrayBuffer) await appendChunk(sourceBuffer, data);
|
|
2141
|
+
else for await (const chunk of data) {
|
|
2142
|
+
if (signal?.aborted) throw signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
2143
|
+
await appendChunk(sourceBuffer, chunk);
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
async function appendChunk(sourceBuffer, data) {
|
|
2102
2147
|
if (sourceBuffer.updating) await new Promise((resolve) => {
|
|
2103
2148
|
const onUpdateEnd = () => {
|
|
2104
2149
|
sourceBuffer.removeEventListener("updateend", onUpdateEnd);
|
|
@@ -2122,7 +2167,7 @@ async function appendSegment(sourceBuffer, segmentData) {
|
|
|
2122
2167
|
sourceBuffer.addEventListener("updateend", onUpdateEnd);
|
|
2123
2168
|
sourceBuffer.addEventListener("error", onError);
|
|
2124
2169
|
try {
|
|
2125
|
-
sourceBuffer.appendBuffer(
|
|
2170
|
+
sourceBuffer.appendBuffer(data);
|
|
2126
2171
|
} catch (error) {
|
|
2127
2172
|
cleanup();
|
|
2128
2173
|
reject(error);
|
|
@@ -2570,7 +2615,7 @@ function isLastSegmentAppended(segments, actor) {
|
|
|
2570
2615
|
if (segments.length === 0) return true;
|
|
2571
2616
|
const lastSeg = segments[segments.length - 1];
|
|
2572
2617
|
if (!lastSeg) return false;
|
|
2573
|
-
return actor?.snapshot.context.segments.some((s) => s.id === lastSeg.id) ?? false;
|
|
2618
|
+
return actor?.snapshot.context.segments.some((s) => s.id === lastSeg.id && !s.partial) ?? false;
|
|
2574
2619
|
}
|
|
2575
2620
|
/**
|
|
2576
2621
|
* Check if the last segment has been appended for each selected track.
|
|
@@ -2800,14 +2845,26 @@ function appendInitTask(message, { signal, getCtx, sourceBuffer }) {
|
|
|
2800
2845
|
};
|
|
2801
2846
|
}, { signal });
|
|
2802
2847
|
}
|
|
2803
|
-
function appendSegmentTask(message, { signal, getCtx, sourceBuffer }) {
|
|
2848
|
+
function appendSegmentTask(message, { signal, getCtx, sourceBuffer, onPartialContext }) {
|
|
2804
2849
|
return new Task(async (taskSignal) => {
|
|
2805
2850
|
const ctx = getCtx();
|
|
2806
2851
|
if (taskSignal.aborted) return ctx;
|
|
2807
|
-
await appendSegment(sourceBuffer, message.data);
|
|
2808
2852
|
const { meta } = message;
|
|
2809
2853
|
const EPSILON = 1e-4;
|
|
2810
2854
|
const filtered = ctx.segments.filter((s) => Math.abs(s.startTime - meta.startTime) >= EPSILON);
|
|
2855
|
+
if (!(message.data instanceof ArrayBuffer)) onPartialContext({
|
|
2856
|
+
...ctx,
|
|
2857
|
+
segments: [...filtered, {
|
|
2858
|
+
id: meta.id,
|
|
2859
|
+
startTime: meta.startTime,
|
|
2860
|
+
duration: meta.duration,
|
|
2861
|
+
trackId: meta.trackId,
|
|
2862
|
+
...meta.trackBandwidth !== void 0 && { trackBandwidth: meta.trackBandwidth },
|
|
2863
|
+
partial: true
|
|
2864
|
+
}],
|
|
2865
|
+
bufferedRanges: ctx.bufferedRanges
|
|
2866
|
+
});
|
|
2867
|
+
await appendSegment(sourceBuffer, message.data, taskSignal);
|
|
2811
2868
|
return {
|
|
2812
2869
|
...ctx,
|
|
2813
2870
|
segments: [...filtered, {
|
|
@@ -2882,10 +2939,18 @@ function createSourceBufferActor(sourceBuffer, initialContext) {
|
|
|
2882
2939
|
send(message, signal) {
|
|
2883
2940
|
if (state.current.status !== "idle") return Promise.reject(new SourceBufferActorError(`send() called while actor is ${state.current.status}`));
|
|
2884
2941
|
state.patch({ status: "updating" });
|
|
2942
|
+
const onPartialContext = (ctx) => {
|
|
2943
|
+
state.patch({
|
|
2944
|
+
status: "updating",
|
|
2945
|
+
context: ctx
|
|
2946
|
+
});
|
|
2947
|
+
state.flush();
|
|
2948
|
+
};
|
|
2885
2949
|
const task = messageToTask(message, {
|
|
2886
2950
|
signal,
|
|
2887
2951
|
getCtx: () => state.current.context,
|
|
2888
|
-
sourceBuffer
|
|
2952
|
+
sourceBuffer,
|
|
2953
|
+
onPartialContext
|
|
2889
2954
|
});
|
|
2890
2955
|
return runner.schedule(task).then(applyResult).catch(handleError);
|
|
2891
2956
|
},
|
|
@@ -2894,11 +2959,19 @@ function createSourceBufferActor(sourceBuffer, initialContext) {
|
|
|
2894
2959
|
if (messages.length === 0) return Promise.resolve();
|
|
2895
2960
|
state.patch({ status: "updating" });
|
|
2896
2961
|
let workingCtx = state.current.context;
|
|
2962
|
+
const onPartialContext = (ctx) => {
|
|
2963
|
+
state.patch({
|
|
2964
|
+
status: "updating",
|
|
2965
|
+
context: ctx
|
|
2966
|
+
});
|
|
2967
|
+
state.flush();
|
|
2968
|
+
};
|
|
2897
2969
|
for (const message of messages.slice(0, -1)) {
|
|
2898
2970
|
const task = messageToTask(message, {
|
|
2899
2971
|
signal,
|
|
2900
2972
|
getCtx: () => workingCtx,
|
|
2901
|
-
sourceBuffer
|
|
2973
|
+
sourceBuffer,
|
|
2974
|
+
onPartialContext
|
|
2902
2975
|
});
|
|
2903
2976
|
runner.schedule(task).then((newCtx) => {
|
|
2904
2977
|
workingCtx = newCtx;
|
|
@@ -2907,7 +2980,8 @@ function createSourceBufferActor(sourceBuffer, initialContext) {
|
|
|
2907
2980
|
const lastTask = messageToTask(messages[messages.length - 1], {
|
|
2908
2981
|
signal,
|
|
2909
2982
|
getCtx: () => workingCtx,
|
|
2910
|
-
sourceBuffer
|
|
2983
|
+
sourceBuffer,
|
|
2984
|
+
onPartialContext
|
|
2911
2985
|
});
|
|
2912
2986
|
return runner.schedule(lastTask).then(applyResult).catch(handleError);
|
|
2913
2987
|
},
|
|
@@ -2921,30 +2995,6 @@ function createSourceBufferActor(sourceBuffer, initialContext) {
|
|
|
2921
2995
|
|
|
2922
2996
|
//#endregion
|
|
2923
2997
|
//#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
2998
|
/**
|
|
2949
2999
|
* Build MIME codec string from track metadata.
|
|
2950
3000
|
*
|
|
@@ -2960,66 +3010,47 @@ function buildMimeCodec(track) {
|
|
|
2960
3010
|
return `${track.mimeType}; codecs="${codecString}"`;
|
|
2961
3011
|
}
|
|
2962
3012
|
/**
|
|
2963
|
-
*
|
|
3013
|
+
* Setup all needed SourceBuffers as a single coordinated operation.
|
|
2964
3014
|
*
|
|
2965
|
-
*
|
|
2966
|
-
*
|
|
2967
|
-
*
|
|
3015
|
+
* Waits until ALL selected tracks (video and/or audio) are resolved with
|
|
3016
|
+
* codecs, then creates every SourceBuffer in one synchronous block before
|
|
3017
|
+
* patching owners. This guarantees that downstream consumers (e.g.
|
|
3018
|
+
* loadSegments) never see a partial set of SourceBuffers — preventing the
|
|
3019
|
+
* Firefox bug where appending to a video SourceBuffer before the audio
|
|
3020
|
+
* SourceBuffer exists causes mozHasAudio to be permanently false.
|
|
2968
3021
|
*
|
|
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.
|
|
3022
|
+
* Handles video-only, audio-only, and combined presentations correctly:
|
|
3023
|
+
* only the tracks that are actually selected are waited on and created.
|
|
2973
3024
|
*
|
|
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
3025
|
* @example
|
|
3003
|
-
* const
|
|
3004
|
-
* const audioCleanup = setupSourceBuffer({ state, owners }, { type: 'audio' });
|
|
3026
|
+
* const cleanup = setupSourceBuffers({ state, owners });
|
|
3005
3027
|
*/
|
|
3006
|
-
function
|
|
3007
|
-
let
|
|
3028
|
+
function setupSourceBuffers({ state, owners }) {
|
|
3029
|
+
let setupDone = false;
|
|
3008
3030
|
return combineLatest([state, owners]).subscribe(async ([currentState, currentOwners]) => {
|
|
3009
|
-
if (
|
|
3010
|
-
if (!
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3031
|
+
if (setupDone) return;
|
|
3032
|
+
if (!currentOwners.mediaSource) return;
|
|
3033
|
+
const videoSelected = !!currentState.selectedVideoTrackId;
|
|
3034
|
+
const audioSelected = !!currentState.selectedAudioTrackId;
|
|
3035
|
+
if (!videoSelected && !audioSelected) return;
|
|
3036
|
+
const videoTrack = videoSelected ? getSelectedTrack(currentState, "video") : null;
|
|
3037
|
+
const audioTrack = audioSelected ? getSelectedTrack(currentState, "audio") : null;
|
|
3038
|
+
if (videoSelected && (!videoTrack || !isResolvedTrack(videoTrack) || !videoTrack.codecs?.length)) return;
|
|
3039
|
+
if (audioSelected && (!audioTrack || !isResolvedTrack(audioTrack) || !audioTrack.codecs?.length)) return;
|
|
3040
|
+
setupDone = true;
|
|
3041
|
+
const patch = {};
|
|
3042
|
+
if (videoSelected && videoTrack && isResolvedTrack(videoTrack)) {
|
|
3043
|
+
const buffer = createSourceBuffer(currentOwners.mediaSource, buildMimeCodec(videoTrack));
|
|
3044
|
+
patch.videoBuffer = buffer;
|
|
3045
|
+
patch.videoBufferActor = createSourceBufferActor(buffer);
|
|
3046
|
+
}
|
|
3047
|
+
if (audioSelected && audioTrack && isResolvedTrack(audioTrack)) {
|
|
3048
|
+
const buffer = createSourceBuffer(currentOwners.mediaSource, buildMimeCodec(audioTrack));
|
|
3049
|
+
patch.audioBuffer = buffer;
|
|
3050
|
+
patch.audioBufferActor = createSourceBufferActor(buffer);
|
|
3022
3051
|
}
|
|
3052
|
+
owners.patch(patch);
|
|
3053
|
+
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
3023
3054
|
});
|
|
3024
3055
|
}
|
|
3025
3056
|
|
|
@@ -3371,14 +3402,10 @@ function createPlaybackEngine(config = {}) {
|
|
|
3371
3402
|
state,
|
|
3372
3403
|
owners
|
|
3373
3404
|
}),
|
|
3374
|
-
|
|
3405
|
+
setupSourceBuffers({
|
|
3375
3406
|
state,
|
|
3376
3407
|
owners
|
|
3377
|
-
}
|
|
3378
|
-
setupSourceBuffer({
|
|
3379
|
-
state,
|
|
3380
|
-
owners
|
|
3381
|
-
}, { type: "audio" }),
|
|
3408
|
+
}),
|
|
3382
3409
|
trackCurrentTime({
|
|
3383
3410
|
state,
|
|
3384
3411
|
owners
|
|
@@ -3509,4 +3536,4 @@ var SpfMedia = class {
|
|
|
3509
3536
|
|
|
3510
3537
|
//#endregion
|
|
3511
3538
|
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-
|
|
3539
|
+
//# sourceMappingURL=adapter-ClnRGbQf.js.map
|