hls.js 1.6.0-rc.1.0.canary.11078 → 1.6.0-rc.1.0.canary.11080
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/hls.d.mts +12 -3
- package/dist/hls.d.ts +12 -3
- package/dist/hls.js +270 -146
- package/dist/hls.js.d.ts +12 -3
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +102 -66
- package/dist/hls.light.js.map +1 -1
- package/dist/hls.light.min.js +1 -1
- package/dist/hls.light.min.js.map +1 -1
- package/dist/hls.light.mjs +59 -28
- package/dist/hls.light.mjs.map +1 -1
- package/dist/hls.min.js +1 -1
- package/dist/hls.min.js.map +1 -1
- package/dist/hls.mjs +191 -75
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/package.json +1 -1
- package/src/controller/audio-stream-controller.ts +7 -7
- package/src/controller/base-stream-controller.ts +44 -11
- package/src/controller/buffer-controller.ts +21 -13
- package/src/controller/interstitial-player.ts +30 -0
- package/src/controller/interstitials-controller.ts +69 -21
- package/src/controller/interstitials-schedule.ts +14 -10
- package/src/controller/latency-controller.ts +16 -2
- package/src/controller/stream-controller.ts +9 -8
- package/src/controller/subtitle-stream-controller.ts +4 -5
- package/src/loader/interstitial-asset-list.ts +3 -13
- package/src/loader/interstitial-event.ts +20 -2
package/dist/hls.mjs
CHANGED
@@ -402,7 +402,7 @@ function enableLogs(debugConfig, context, id) {
|
|
402
402
|
// Some browsers don't allow to use bind on console object anyway
|
403
403
|
// fallback to default if needed
|
404
404
|
try {
|
405
|
-
newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.0-rc.1.0.canary.
|
405
|
+
newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.0-rc.1.0.canary.11080"}`);
|
406
406
|
} catch (e) {
|
407
407
|
/* log fn threw an exception. All logger methods are no-ops. */
|
408
408
|
return createLogger();
|
@@ -8453,6 +8453,14 @@ class BaseStreamController extends TaskLoop {
|
|
8453
8453
|
return (_this$levelLastLoaded = this.levelLastLoaded) == null ? void 0 : _this$levelLastLoaded.details;
|
8454
8454
|
}
|
8455
8455
|
}
|
8456
|
+
get timelineOffset() {
|
8457
|
+
const configuredTimelineOffset = this.config.timelineOffset;
|
8458
|
+
if (configuredTimelineOffset) {
|
8459
|
+
var _this$getLevelDetails;
|
8460
|
+
return ((_this$getLevelDetails = this.getLevelDetails()) == null ? void 0 : _this$getLevelDetails.appliedTimelineOffset) || configuredTimelineOffset;
|
8461
|
+
}
|
8462
|
+
return 0;
|
8463
|
+
}
|
8456
8464
|
onMediaAttached(event, data) {
|
8457
8465
|
const media = this.media = this.mediaBuffer = data.media;
|
8458
8466
|
media.removeEventListener('seeking', this.onMediaSeeking);
|
@@ -9150,8 +9158,8 @@ class BaseStreamController extends TaskLoop {
|
|
9150
9158
|
const end = this.loadingParts ? levelDetails.partEnd : levelDetails.fragmentEnd;
|
9151
9159
|
frag = this.getFragmentAtPosition(pos, end, levelDetails);
|
9152
9160
|
}
|
9153
|
-
|
9154
|
-
return this.mapToInitFragWhenRequired(
|
9161
|
+
const programFrag = this.filterReplacedPrimary(frag, levelDetails);
|
9162
|
+
return this.mapToInitFragWhenRequired(programFrag);
|
9155
9163
|
}
|
9156
9164
|
isLoopLoading(frag, targetBufferTime) {
|
9157
9165
|
const trackerState = this.fragmentTracker.getState(frag);
|
@@ -9178,12 +9186,21 @@ class BaseStreamController extends TaskLoop {
|
|
9178
9186
|
this.loopSn = undefined;
|
9179
9187
|
return nextFragment;
|
9180
9188
|
}
|
9189
|
+
get primaryPrefetch() {
|
9190
|
+
if (interstitialsEnabled(this.hls.config)) {
|
9191
|
+
var _this$hls$interstitia, _this$hls$interstitia2;
|
9192
|
+
const playingInterstitial = (_this$hls$interstitia = this.hls.interstitialsManager) == null ? void 0 : (_this$hls$interstitia2 = _this$hls$interstitia.playingItem) == null ? void 0 : _this$hls$interstitia2.event;
|
9193
|
+
if (playingInterstitial) {
|
9194
|
+
return true;
|
9195
|
+
}
|
9196
|
+
}
|
9197
|
+
return false;
|
9198
|
+
}
|
9181
9199
|
filterReplacedPrimary(frag, details) {
|
9182
9200
|
if (!frag) {
|
9183
9201
|
return frag;
|
9184
9202
|
}
|
9185
|
-
|
9186
|
-
if (config.interstitialsController && config.enableInterstitialPlayback !== false && frag.type !== PlaylistLevelType.SUBTITLE) {
|
9203
|
+
if (interstitialsEnabled(this.hls.config) && frag.type !== PlaylistLevelType.SUBTITLE) {
|
9187
9204
|
// Do not load fragments outside the buffering schedule segment
|
9188
9205
|
const interstitials = this.hls.interstitialsManager;
|
9189
9206
|
const bufferingItem = interstitials == null ? void 0 : interstitials.bufferingItem;
|
@@ -9203,7 +9220,10 @@ class BaseStreamController extends TaskLoop {
|
|
9203
9220
|
}
|
9204
9221
|
if (frag.start > bufferingItem.end && bufferingItem.nextEvent) {
|
9205
9222
|
// fragment is past schedule item end
|
9206
|
-
|
9223
|
+
// allow some overflow when not appending in place to prevent stalls
|
9224
|
+
if (bufferingItem.nextEvent.appendInPlace || frag.start - bufferingItem.end > 1) {
|
9225
|
+
return null;
|
9226
|
+
}
|
9207
9227
|
}
|
9208
9228
|
}
|
9209
9229
|
}
|
@@ -9389,6 +9409,7 @@ class BaseStreamController extends TaskLoop {
|
|
9389
9409
|
if (startPosition < sliding) {
|
9390
9410
|
startPosition = -1;
|
9391
9411
|
}
|
9412
|
+
const timelineOffset = this.timelineOffset;
|
9392
9413
|
if (startPosition === -1) {
|
9393
9414
|
// Use Playlist EXT-X-START:TIME-OFFSET when set
|
9394
9415
|
// Prioritize Multivariant Playlist offset so that main, audio, and subtitle stream-controller start times match
|
@@ -9412,9 +9433,9 @@ class BaseStreamController extends TaskLoop {
|
|
9412
9433
|
this.log(`setting startPosition to 0 by default`);
|
9413
9434
|
this.startPosition = startPosition = 0;
|
9414
9435
|
}
|
9415
|
-
this.lastCurrentTime = startPosition;
|
9436
|
+
this.lastCurrentTime = startPosition + timelineOffset;
|
9416
9437
|
}
|
9417
|
-
this.nextLoadPosition = startPosition;
|
9438
|
+
this.nextLoadPosition = startPosition + timelineOffset;
|
9418
9439
|
}
|
9419
9440
|
getLoadPosition() {
|
9420
9441
|
var _this$hls;
|
@@ -9694,6 +9715,9 @@ class BaseStreamController extends TaskLoop {
|
|
9694
9715
|
return this._state;
|
9695
9716
|
}
|
9696
9717
|
}
|
9718
|
+
function interstitialsEnabled(config) {
|
9719
|
+
return !!config.interstitialsController && config.enableInterstitialPlayback !== false;
|
9720
|
+
}
|
9697
9721
|
|
9698
9722
|
class ChunkCache {
|
9699
9723
|
constructor() {
|
@@ -10086,7 +10110,7 @@ function requireEventemitter3 () {
|
|
10086
10110
|
var eventemitter3Exports = requireEventemitter3();
|
10087
10111
|
var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
|
10088
10112
|
|
10089
|
-
const version = "1.6.0-rc.1.0.canary.
|
10113
|
+
const version = "1.6.0-rc.1.0.canary.11080";
|
10090
10114
|
|
10091
10115
|
// ensure the worker ends up in the bundle
|
10092
10116
|
// If the worker should not be included this gets aliased to empty.js
|
@@ -16441,7 +16465,7 @@ class AudioStreamController extends BaseStreamController {
|
|
16441
16465
|
const cc = mainFrag.cc;
|
16442
16466
|
return findNearestWithCC(trackDetails, cc, mainFrag) || trackDetails && findFragWithCC(trackDetails.fragments, cc) || mainFrag;
|
16443
16467
|
}
|
16444
|
-
startLoad(startPosition) {
|
16468
|
+
startLoad(startPosition, skipSeekToStartPosition) {
|
16445
16469
|
if (!this.levels) {
|
16446
16470
|
this.startPosition = startPosition;
|
16447
16471
|
this.state = State.STOPPED;
|
@@ -16457,7 +16481,8 @@ class AudioStreamController extends BaseStreamController {
|
|
16457
16481
|
} else {
|
16458
16482
|
this.state = State.WAITING_TRACK;
|
16459
16483
|
}
|
16460
|
-
this.nextLoadPosition = this.
|
16484
|
+
this.nextLoadPosition = this.lastCurrentTime = startPosition + this.timelineOffset;
|
16485
|
+
this.startPosition = skipSeekToStartPosition ? -1 : startPosition;
|
16461
16486
|
this.tick();
|
16462
16487
|
}
|
16463
16488
|
doTick() {
|
@@ -16581,7 +16606,7 @@ class AudioStreamController extends BaseStreamController {
|
|
16581
16606
|
// 3. if tracks or track not loaded and selected
|
16582
16607
|
// then exit loop
|
16583
16608
|
// => if media not attached but start frag prefetch is enabled and start frag not requested yet, we will not exit loop
|
16584
|
-
if (!this.buffering || !media && (this.startFragRequested || !config.startFragPrefetch) || !(levels != null && levels[trackId])) {
|
16609
|
+
if (!this.buffering || !media && !this.primaryPrefetch && (this.startFragRequested || !config.startFragPrefetch) || !(levels != null && levels[trackId])) {
|
16585
16610
|
return;
|
16586
16611
|
}
|
16587
16612
|
const levelInfo = levels[trackId];
|
@@ -18822,17 +18847,10 @@ transfer tracks: ${stringify(transferredTracks, (key, value) => key === 'initSeg
|
|
18822
18847
|
return type && !((_this$tracks$type4 = this.tracks[type]) != null && _this$tracks$type4.ended);
|
18823
18848
|
});
|
18824
18849
|
if (allTracksEnding) {
|
18825
|
-
|
18826
|
-
|
18827
|
-
this.
|
18828
|
-
|
18829
|
-
const track = this.tracks[type];
|
18830
|
-
if (track) {
|
18831
|
-
track.ending = false;
|
18832
|
-
}
|
18833
|
-
}
|
18834
|
-
});
|
18835
|
-
if (allowEndOfStream) {
|
18850
|
+
if (allowEndOfStream) {
|
18851
|
+
this.log(`Queueing EOS`);
|
18852
|
+
this.blockUntilOpen(() => {
|
18853
|
+
this.tracksEnded();
|
18836
18854
|
const {
|
18837
18855
|
mediaSource
|
18838
18856
|
} = this;
|
@@ -18845,11 +18863,24 @@ transfer tracks: ${stringify(transferredTracks, (key, value) => key === 'initSeg
|
|
18845
18863
|
this.log(`Calling mediaSource.endOfStream()`);
|
18846
18864
|
// Allow this to throw and be caught by the enqueueing function
|
18847
18865
|
mediaSource.endOfStream();
|
18848
|
-
|
18866
|
+
this.hls.trigger(Events.BUFFERED_TO_END, undefined);
|
18867
|
+
});
|
18868
|
+
} else {
|
18869
|
+
this.tracksEnded();
|
18849
18870
|
this.hls.trigger(Events.BUFFERED_TO_END, undefined);
|
18850
|
-
}
|
18871
|
+
}
|
18851
18872
|
}
|
18852
18873
|
}
|
18874
|
+
tracksEnded() {
|
18875
|
+
this.sourceBuffers.forEach(([type]) => {
|
18876
|
+
if (type !== null) {
|
18877
|
+
const track = this.tracks[type];
|
18878
|
+
if (track) {
|
18879
|
+
track.ending = false;
|
18880
|
+
}
|
18881
|
+
}
|
18882
|
+
});
|
18883
|
+
}
|
18853
18884
|
onLevelUpdated(event, {
|
18854
18885
|
details
|
18855
18886
|
}) {
|
@@ -22980,7 +23011,7 @@ function hash(text) {
|
|
22980
23011
|
return (hash >>> 0).toString();
|
22981
23012
|
}
|
22982
23013
|
|
22983
|
-
const ALIGNED_END_THRESHOLD_SECONDS = 0.
|
23014
|
+
const ALIGNED_END_THRESHOLD_SECONDS = 0.025;
|
22984
23015
|
let TimelineOccupancy = /*#__PURE__*/function (TimelineOccupancy) {
|
22985
23016
|
TimelineOccupancy[TimelineOccupancy["Point"] = 0] = "Point";
|
22986
23017
|
TimelineOccupancy[TimelineOccupancy["Range"] = 1] = "Range";
|
@@ -23014,6 +23045,7 @@ class InterstitialEvent {
|
|
23014
23045
|
this.assetListResponse = null;
|
23015
23046
|
this.resumeAnchor = void 0;
|
23016
23047
|
this.error = void 0;
|
23048
|
+
this.resetOnResume = void 0;
|
23017
23049
|
this.base = base;
|
23018
23050
|
this.dateRange = dateRange;
|
23019
23051
|
this.setDateRange(dateRange);
|
@@ -23073,6 +23105,18 @@ class InterstitialEvent {
|
|
23073
23105
|
get startOffset() {
|
23074
23106
|
return this.cue.pre ? 0 : this.startTime;
|
23075
23107
|
}
|
23108
|
+
get startIsAligned() {
|
23109
|
+
if (this.startTime === 0 || this.snapOptions.out) {
|
23110
|
+
return true;
|
23111
|
+
}
|
23112
|
+
const frag = this.dateRange.tagAnchor;
|
23113
|
+
if (frag) {
|
23114
|
+
const startTime = this.dateRange.startTime;
|
23115
|
+
const snappedStart = getSnapToFragmentTime(startTime, frag);
|
23116
|
+
return startTime - snappedStart < 0.1;
|
23117
|
+
}
|
23118
|
+
return false;
|
23119
|
+
}
|
23076
23120
|
get resumptionOffset() {
|
23077
23121
|
const resumeOffset = this.resumeOffset;
|
23078
23122
|
const offset = isFiniteNumber(resumeOffset) ? resumeOffset : this.duration;
|
@@ -23090,18 +23134,22 @@ class InterstitialEvent {
|
|
23090
23134
|
return resumeTime;
|
23091
23135
|
}
|
23092
23136
|
get appendInPlace() {
|
23137
|
+
if (this.appendInPlaceStarted) {
|
23138
|
+
return true;
|
23139
|
+
}
|
23093
23140
|
if (this.appendInPlaceDisabled) {
|
23094
23141
|
return false;
|
23095
23142
|
}
|
23096
|
-
if (!this.cue.once && !this.cue.pre &&
|
23143
|
+
if (!this.cue.once && !this.cue.pre &&
|
23097
23144
|
// preroll starts at startPosition before startPosition is known (live)
|
23098
|
-
this.
|
23145
|
+
this.startIsAligned && (isNaN(this.playoutLimit) && isNaN(this.resumeOffset) || this.resumeOffset && this.duration && Math.abs(this.resumeOffset - this.duration) < ALIGNED_END_THRESHOLD_SECONDS)) {
|
23099
23146
|
return true;
|
23100
23147
|
}
|
23101
23148
|
return false;
|
23102
23149
|
}
|
23103
23150
|
set appendInPlace(value) {
|
23104
23151
|
if (this.appendInPlaceStarted) {
|
23152
|
+
this.resetOnResume = !value;
|
23105
23153
|
return;
|
23106
23154
|
}
|
23107
23155
|
this.appendInPlaceDisabled = !value;
|
@@ -23194,6 +23242,7 @@ class HlsAssetPlayer {
|
|
23194
23242
|
this.hasDetails = false;
|
23195
23243
|
this.mediaAttached = null;
|
23196
23244
|
this._currentTime = void 0;
|
23245
|
+
this._bufferedEosTime = void 0;
|
23197
23246
|
this.checkPlayout = () => {
|
23198
23247
|
const interstitial = this.interstitial;
|
23199
23248
|
const playoutLimit = interstitial.playoutLimit;
|
@@ -23230,9 +23279,25 @@ class HlsAssetPlayer {
|
|
23230
23279
|
}
|
23231
23280
|
});
|
23232
23281
|
}
|
23233
|
-
|
23282
|
+
bufferedInPlaceToEnd(media) {
|
23234
23283
|
var _this$hls;
|
23235
|
-
|
23284
|
+
if (!this.interstitial.appendInPlace) {
|
23285
|
+
return false;
|
23286
|
+
}
|
23287
|
+
if ((_this$hls = this.hls) != null && _this$hls.bufferedToEnd) {
|
23288
|
+
return true;
|
23289
|
+
}
|
23290
|
+
if (!media || !this._bufferedEosTime) {
|
23291
|
+
return false;
|
23292
|
+
}
|
23293
|
+
const start = this.timelineOffset;
|
23294
|
+
const bufferInfo = BufferHelper.bufferInfo(media, start, 0);
|
23295
|
+
const bufferedEnd = this.getAssetTime(bufferInfo.end);
|
23296
|
+
return bufferedEnd >= this._bufferedEosTime - 0.02;
|
23297
|
+
}
|
23298
|
+
get destroyed() {
|
23299
|
+
var _this$hls2;
|
23300
|
+
return !((_this$hls2 = this.hls) != null && _this$hls2.userConfig);
|
23236
23301
|
}
|
23237
23302
|
get assetId() {
|
23238
23303
|
return this.assetItem.identifier;
|
@@ -23241,12 +23306,15 @@ class HlsAssetPlayer {
|
|
23241
23306
|
return this.assetItem.parentIdentifier;
|
23242
23307
|
}
|
23243
23308
|
get media() {
|
23244
|
-
var _this$
|
23245
|
-
return ((_this$
|
23309
|
+
var _this$hls3;
|
23310
|
+
return ((_this$hls3 = this.hls) == null ? void 0 : _this$hls3.media) || null;
|
23246
23311
|
}
|
23247
23312
|
get bufferedEnd() {
|
23248
23313
|
const media = this.media || this.mediaAttached;
|
23249
23314
|
if (!media) {
|
23315
|
+
if (this._bufferedEosTime) {
|
23316
|
+
return this._bufferedEosTime;
|
23317
|
+
}
|
23250
23318
|
return this.currentTime;
|
23251
23319
|
}
|
23252
23320
|
const bufferInfo = BufferHelper.bufferInfo(media, media.currentTime, 0.001);
|
@@ -23277,8 +23345,8 @@ class HlsAssetPlayer {
|
|
23277
23345
|
return this.assetItem.startOffset;
|
23278
23346
|
}
|
23279
23347
|
get timelineOffset() {
|
23280
|
-
var _this$
|
23281
|
-
return ((_this$
|
23348
|
+
var _this$hls4;
|
23349
|
+
return ((_this$hls4 = this.hls) == null ? void 0 : _this$hls4.config.timelineOffset) || 0;
|
23282
23350
|
}
|
23283
23351
|
set timelineOffset(value) {
|
23284
23352
|
const timelineOffset = this.timelineOffset;
|
@@ -23301,9 +23369,18 @@ class HlsAssetPlayer {
|
|
23301
23369
|
const media = this.mediaAttached;
|
23302
23370
|
if (media) {
|
23303
23371
|
this._currentTime = media.currentTime;
|
23372
|
+
this.bufferSnapShot();
|
23304
23373
|
media.removeEventListener('timeupdate', this.checkPlayout);
|
23305
23374
|
}
|
23306
23375
|
}
|
23376
|
+
bufferSnapShot() {
|
23377
|
+
if (this.mediaAttached) {
|
23378
|
+
var _this$hls5;
|
23379
|
+
if ((_this$hls5 = this.hls) != null && _this$hls5.bufferedToEnd) {
|
23380
|
+
this._bufferedEosTime = this.bufferedEnd;
|
23381
|
+
}
|
23382
|
+
}
|
23383
|
+
}
|
23307
23384
|
destroy() {
|
23308
23385
|
this.removeMediaListeners();
|
23309
23386
|
this.hls.destroy();
|
@@ -23327,6 +23404,7 @@ class HlsAssetPlayer {
|
|
23327
23404
|
this.hls.pauseBuffering();
|
23328
23405
|
}
|
23329
23406
|
transferMedia() {
|
23407
|
+
this.bufferSnapShot();
|
23330
23408
|
return this.hls.transferMedia();
|
23331
23409
|
}
|
23332
23410
|
on(event, listener, context) {
|
@@ -23339,8 +23417,8 @@ class HlsAssetPlayer {
|
|
23339
23417
|
this.hls.off(event, listener);
|
23340
23418
|
}
|
23341
23419
|
toString() {
|
23342
|
-
var _this$
|
23343
|
-
return `HlsAssetPlayer: ${eventAssetToString(this.assetItem)} ${(_this$
|
23420
|
+
var _this$hls6, _this$interstitial;
|
23421
|
+
return `HlsAssetPlayer: ${eventAssetToString(this.assetItem)} ${(_this$hls6 = this.hls) == null ? void 0 : _this$hls6.sessionId} ${(_this$interstitial = this.interstitial) != null && _this$interstitial.appendInPlace ? 'append-in-place' : ''}`;
|
23344
23422
|
}
|
23345
23423
|
}
|
23346
23424
|
|
@@ -23787,6 +23865,9 @@ class InterstitialsSchedule extends Logger {
|
|
23787
23865
|
const timeBetween = interstitialEvents[i + 1].startTime - interstitialEvents[i].resumeTime;
|
23788
23866
|
if (timeBetween < ABUTTING_THRESHOLD_SECONDS) {
|
23789
23867
|
interstitialEvents[i + 1].appendInPlace = false;
|
23868
|
+
if (interstitialEvents[i + 1].appendInPlace) {
|
23869
|
+
this.warn(`Could not change append strategy for abutting event ${interstitial}`);
|
23870
|
+
}
|
23790
23871
|
}
|
23791
23872
|
}
|
23792
23873
|
// Update cumulativeDuration for next abutting interstitial with the same start date
|
@@ -23810,19 +23891,18 @@ class InterstitialsSchedule extends Logger {
|
|
23810
23891
|
const details = mediaSelection[playlistType].details;
|
23811
23892
|
const playlistEnd = details.edge;
|
23812
23893
|
if (resumeTime > playlistEnd) {
|
23813
|
-
|
23814
|
-
|
23815
|
-
|
23816
|
-
}
|
23894
|
+
// Live playback - resumption segments are not yet available
|
23895
|
+
this.log(`"${interstitial.identifier}" resumption ${resumeTime} past ${playlistType} playlist end ${playlistEnd}`);
|
23896
|
+
// Assume alignment is possible (or reset can take place)
|
23817
23897
|
return false;
|
23818
23898
|
}
|
23819
23899
|
const startFragment = findFragmentByPTS(null, details.fragments, resumeTime);
|
23820
23900
|
if (!startFragment) {
|
23821
|
-
this.log(`"${interstitial.identifier}" resumption ${resumeTime} does not align with any fragments in ${playlistType} playlist`);
|
23901
|
+
this.log(`"${interstitial.identifier}" resumption ${resumeTime} does not align with any fragments in ${playlistType} playlist (${details.fragStart}-${details.fragmentEnd})`);
|
23822
23902
|
return true;
|
23823
23903
|
}
|
23824
|
-
const
|
23825
|
-
const alignedWithSegment = Math.abs(startFragment.start - resumeTime) < ALIGNED_END_THRESHOLD_SECONDS || Math.abs(startFragment.end - resumeTime) < ALIGNED_END_THRESHOLD_SECONDS +
|
23904
|
+
const allowance = playlistType === 'audio' ? 0.175 : 0;
|
23905
|
+
const alignedWithSegment = Math.abs(startFragment.start - resumeTime) < ALIGNED_END_THRESHOLD_SECONDS + allowance || Math.abs(startFragment.end - resumeTime) < ALIGNED_END_THRESHOLD_SECONDS + allowance;
|
23826
23906
|
if (!alignedWithSegment) {
|
23827
23907
|
this.log(`"${interstitial.identifier}" resumption ${resumeTime} not aligned with ${playlistType} fragment bounds (${startFragment.start}-${startFragment.end} sn: ${startFragment.sn} cc: ${startFragment.cc})`);
|
23828
23908
|
return true;
|
@@ -23872,7 +23952,7 @@ class AssetListLoader {
|
|
23872
23952
|
// @ts-ignore
|
23873
23953
|
this.hls = null;
|
23874
23954
|
}
|
23875
|
-
loadAssetList(interstitial,
|
23955
|
+
loadAssetList(interstitial, hlsStartOffset) {
|
23876
23956
|
const assetListUrl = interstitial.assetListUrl;
|
23877
23957
|
let url;
|
23878
23958
|
try {
|
@@ -23882,11 +23962,8 @@ class AssetListLoader {
|
|
23882
23962
|
this.hls.trigger(Events.ERROR, errorData);
|
23883
23963
|
return;
|
23884
23964
|
}
|
23885
|
-
if (
|
23886
|
-
|
23887
|
-
if (startOffset > 0) {
|
23888
|
-
url.searchParams.set('_HLS_start_offset', '' + Math.round(startOffset * 1000) / 1000);
|
23889
|
-
}
|
23965
|
+
if (hlsStartOffset && url.protocol !== 'data:') {
|
23966
|
+
url.searchParams.set('_HLS_start_offset', '' + hlsStartOffset);
|
23890
23967
|
}
|
23891
23968
|
const config = this.hls.config;
|
23892
23969
|
const Loader = config.loader;
|
@@ -24400,7 +24477,7 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))}`);
|
|
24400
24477
|
if (media) {
|
24401
24478
|
const currentTime = timelineType === 'primary' ? media.currentTime : getMappedTime(playingItem, timelineType, c.playingAsset, 'timelinePos', 'currentTime');
|
24402
24479
|
const diff = time - currentTime;
|
24403
|
-
const seekToTime = media.currentTime + diff;
|
24480
|
+
const seekToTime = (appendInPlace ? currentTime : media.currentTime) + diff;
|
24404
24481
|
if (seekToTime >= 0 && (!assetPlayer || appendInPlace || seekToTime <= assetPlayer.duration)) {
|
24405
24482
|
media.currentTime = seekToTime;
|
24406
24483
|
return;
|
@@ -24550,12 +24627,7 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))}`);
|
|
24550
24627
|
return getBufferedEnd();
|
24551
24628
|
},
|
24552
24629
|
get currentTime() {
|
24553
|
-
var _playingItem$event;
|
24554
24630
|
const timelinePos = c.timelinePos;
|
24555
|
-
const playingItem = c.effectivePlayingItem;
|
24556
|
-
if (playingItem != null && (_playingItem$event = playingItem.event) != null && _playingItem$event.appendInPlace) {
|
24557
|
-
return playingItem.start;
|
24558
|
-
}
|
24559
24631
|
return timelinePos > 0 ? timelinePos : 0;
|
24560
24632
|
},
|
24561
24633
|
set currentTime(time) {
|
@@ -24724,6 +24796,9 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))}`);
|
|
24724
24796
|
const interstitial = queuedPlayer.interstitial;
|
24725
24797
|
this.clearInterstitial(queuedPlayer.interstitial, null);
|
24726
24798
|
interstitial.appendInPlace = false;
|
24799
|
+
if (interstitial.appendInPlace) {
|
24800
|
+
this.warn(`Could not change append strategy for queued assets ${interstitial}`);
|
24801
|
+
}
|
24727
24802
|
}
|
24728
24803
|
});
|
24729
24804
|
}
|
@@ -24900,7 +24975,9 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))}`);
|
|
24900
24975
|
}
|
24901
24976
|
// Ensure Interstitial is enqueued
|
24902
24977
|
const waitingItem = this.waitingItem;
|
24903
|
-
this.
|
24978
|
+
if (!this.assetsBuffered(scheduledItem, media)) {
|
24979
|
+
this.setBufferingItem(scheduledItem);
|
24980
|
+
}
|
24904
24981
|
let player = this.preloadAssets(interstitial, assetListIndex);
|
24905
24982
|
if (!this.eventItemsMatch(scheduledItem, waitingItem || currentItem)) {
|
24906
24983
|
this.waitingItem = scheduledItem;
|
@@ -25256,6 +25333,16 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))}`);
|
|
25256
25333
|
this.bufferedToItem(playingItem);
|
25257
25334
|
}
|
25258
25335
|
}
|
25336
|
+
assetsBuffered(item, media) {
|
25337
|
+
const assetList = item.event.assetList;
|
25338
|
+
if (assetList.length === 0) {
|
25339
|
+
return false;
|
25340
|
+
}
|
25341
|
+
return !item.event.assetList.some(asset => {
|
25342
|
+
const player = this.getAssetPlayer(asset.identifier);
|
25343
|
+
return !(player != null && player.bufferedInPlaceToEnd(media));
|
25344
|
+
});
|
25345
|
+
}
|
25259
25346
|
setBufferingItem(item) {
|
25260
25347
|
const bufferingLast = this.bufferingItem;
|
25261
25348
|
const schedule = this.schedule;
|
@@ -25351,14 +25438,11 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))}`);
|
|
25351
25438
|
const neverLoaded = assetListLength === 0 && !interstitial.assetListLoader;
|
25352
25439
|
const playOnce = interstitial.cue.once;
|
25353
25440
|
if (neverLoaded) {
|
25354
|
-
this.log(`Load interstitial asset ${assetListIndex + 1}/${uri ? 1 : assetListLength} ${interstitial}`);
|
25355
25441
|
const timelineStart = interstitial.timelineStart;
|
25356
25442
|
if (interstitial.appendInPlace) {
|
25357
25443
|
this.flushFrontBuffer(timelineStart + 0.25);
|
25358
25444
|
}
|
25359
|
-
|
25360
|
-
return this.createAsset(interstitial, 0, 0, timelineStart, interstitial.duration, uri);
|
25361
|
-
}
|
25445
|
+
let hlsStartOffset;
|
25362
25446
|
let liveStartPosition = 0;
|
25363
25447
|
if (!this.playingItem && this.primaryLive) {
|
25364
25448
|
liveStartPosition = this.hls.startPosition;
|
@@ -25366,7 +25450,17 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))}`);
|
|
25366
25450
|
liveStartPosition = this.hls.liveSyncPosition || 0;
|
25367
25451
|
}
|
25368
25452
|
}
|
25369
|
-
|
25453
|
+
if (liveStartPosition && !(interstitial.cue.pre || interstitial.cue.post)) {
|
25454
|
+
const startOffset = liveStartPosition - timelineStart;
|
25455
|
+
if (startOffset > 0) {
|
25456
|
+
hlsStartOffset = Math.round(startOffset * 1000) / 1000;
|
25457
|
+
}
|
25458
|
+
}
|
25459
|
+
this.log(`Load interstitial asset ${assetListIndex + 1}/${uri ? 1 : assetListLength} ${interstitial}${hlsStartOffset ? ` live-start: ${liveStartPosition} start-offset: ${hlsStartOffset}` : ''}`);
|
25460
|
+
if (uri) {
|
25461
|
+
return this.createAsset(interstitial, 0, 0, timelineStart, interstitial.duration, uri);
|
25462
|
+
}
|
25463
|
+
const assetListLoader = this.assetListLoader.loadAssetList(interstitial, hlsStartOffset);
|
25370
25464
|
if (assetListLoader) {
|
25371
25465
|
interstitial.assetListLoader = assetListLoader;
|
25372
25466
|
}
|
@@ -25456,7 +25550,7 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))}`);
|
|
25456
25550
|
const selectedAudio = primary.audioTracks[primary.audioTrack];
|
25457
25551
|
const selectedSubtitle = primary.subtitleTracks[primary.subtitleTrack];
|
25458
25552
|
let startPosition = 0;
|
25459
|
-
if (this.primaryLive) {
|
25553
|
+
if (this.primaryLive || interstitial.appendInPlace) {
|
25460
25554
|
const timePastStart = this.timelinePos - assetItem.timelineStart;
|
25461
25555
|
if (timePastStart > 1) {
|
25462
25556
|
const duration = assetItem.duration;
|
@@ -25651,9 +25745,10 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))}`);
|
|
25651
25745
|
player
|
25652
25746
|
});
|
25653
25747
|
}
|
25654
|
-
|
25655
|
-
|
25656
|
-
|
25748
|
+
if (!player.bufferedInPlaceToEnd(media)) {
|
25749
|
+
// detach media and attach to interstitial player if it does not have another element attached
|
25750
|
+
this.bufferAssetPlayer(player, media);
|
25751
|
+
}
|
25657
25752
|
}
|
25658
25753
|
bufferAssetPlayer(player, media) {
|
25659
25754
|
var _this$schedule$items4, _this$detachedData5;
|
@@ -25781,6 +25876,7 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))}`);
|
|
25781
25876
|
return;
|
25782
25877
|
}
|
25783
25878
|
const eventStart = interstitial.timelineStart;
|
25879
|
+
const previousDuration = interstitial.duration;
|
25784
25880
|
let sumDuration = 0;
|
25785
25881
|
assets.forEach((asset, assetListIndex) => {
|
25786
25882
|
const duration = parseFloat(asset.DURATION);
|
@@ -25788,6 +25884,7 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))}`);
|
|
25788
25884
|
sumDuration += duration;
|
25789
25885
|
});
|
25790
25886
|
interstitial.duration = sumDuration;
|
25887
|
+
this.log(`Loaded asset-list with duration: ${sumDuration} (was: ${previousDuration}) ${interstitial}`);
|
25791
25888
|
const waitingItem = this.waitingItem;
|
25792
25889
|
const waitingForItem = (waitingItem == null ? void 0 : waitingItem.event.identifier) === interstitialId;
|
25793
25890
|
|
@@ -25802,6 +25899,15 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))}`);
|
|
25802
25899
|
const scheduleIndex = this.schedule.findEventIndex(interstitialId);
|
25803
25900
|
const item = (_this$schedule$items5 = this.schedule.items) == null ? void 0 : _this$schedule$items5[scheduleIndex];
|
25804
25901
|
if (item) {
|
25902
|
+
if (!this.playingItem && this.timelinePos > item.end) {
|
25903
|
+
// Abandon if new duration is reduced enough to land playback in primary start
|
25904
|
+
const index = this.schedule.findItemIndexAtTime(this.timelinePos);
|
25905
|
+
if (index !== scheduleIndex) {
|
25906
|
+
interstitial.error = new Error(`Interstitial no longer within playback range ${this.timelinePos} ${interstitial}`);
|
25907
|
+
this.primaryFallback(interstitial);
|
25908
|
+
return;
|
25909
|
+
}
|
25910
|
+
}
|
25805
25911
|
this.setBufferingItem(item);
|
25806
25912
|
}
|
25807
25913
|
this.setSchedulePosition(scheduleIndex);
|
@@ -25869,11 +25975,12 @@ class SubtitleStreamController extends BaseStreamController {
|
|
25869
25975
|
hls.off(Events.SUBTITLE_FRAG_PROCESSED, this.onSubtitleFragProcessed, this);
|
25870
25976
|
hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
|
25871
25977
|
}
|
25872
|
-
startLoad(startPosition) {
|
25978
|
+
startLoad(startPosition, skipSeekToStartPosition) {
|
25873
25979
|
this.stopLoad();
|
25874
25980
|
this.state = State.IDLE;
|
25875
25981
|
this.setInterval(TICK_INTERVAL$2);
|
25876
|
-
this.nextLoadPosition = this.
|
25982
|
+
this.nextLoadPosition = this.lastCurrentTime = startPosition + this.timelineOffset;
|
25983
|
+
this.startPosition = skipSeekToStartPosition ? -1 : startPosition;
|
25877
25984
|
this.tick();
|
25878
25985
|
}
|
25879
25986
|
onManifestLoading() {
|
@@ -31090,9 +31197,10 @@ class LatencyController {
|
|
31090
31197
|
if (inLiveRange && distanceFromTarget > 0.05 && this.forwardBufferLength > 1) {
|
31091
31198
|
const max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
|
31092
31199
|
const rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
|
31093
|
-
|
31200
|
+
const playbackRate = Math.min(max, Math.max(1, rate));
|
31201
|
+
this.changeMediaPlaybackRate(media, playbackRate);
|
31094
31202
|
} else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
|
31095
|
-
media
|
31203
|
+
this.changeMediaPlaybackRate(media, 1);
|
31096
31204
|
}
|
31097
31205
|
};
|
31098
31206
|
this.hls = hls;
|
@@ -31251,6 +31359,14 @@ class LatencyController {
|
|
31251
31359
|
this.hls.logger.warn('[latency-controller]: Stall detected, adjusting target latency');
|
31252
31360
|
}
|
31253
31361
|
}
|
31362
|
+
changeMediaPlaybackRate(media, playbackRate) {
|
31363
|
+
var _this$hls2, _this$targetLatency;
|
31364
|
+
if (media.playbackRate === playbackRate) {
|
31365
|
+
return;
|
31366
|
+
}
|
31367
|
+
(_this$hls2 = this.hls) == null ? void 0 : _this$hls2.logger.debug(`[latency-controller]: latency=${this.latency.toFixed(3)}, targetLatency=${(_this$targetLatency = this.targetLatency) == null ? void 0 : _this$targetLatency.toFixed(3)}, forwardBufferLength=${this.forwardBufferLength.toFixed(3)}: adjusting playback rate from ${media.playbackRate} to ${playbackRate}`);
|
31368
|
+
media.playbackRate = playbackRate;
|
31369
|
+
}
|
31254
31370
|
estimateLiveEdge() {
|
31255
31371
|
const levelDetails = this.levelDetails;
|
31256
31372
|
if (levelDetails === null) {
|
@@ -32007,7 +32123,7 @@ class StreamController extends BaseStreamController {
|
|
32007
32123
|
startPosition = lastCurrentTime;
|
32008
32124
|
}
|
32009
32125
|
this.state = State.IDLE;
|
32010
|
-
this.nextLoadPosition = this.lastCurrentTime = startPosition;
|
32126
|
+
this.nextLoadPosition = this.lastCurrentTime = startPosition + this.timelineOffset;
|
32011
32127
|
this.startPosition = skipSeekToStartPosition ? -1 : startPosition;
|
32012
32128
|
this.tick();
|
32013
32129
|
} else {
|
@@ -32083,7 +32199,7 @@ class StreamController extends BaseStreamController {
|
|
32083
32199
|
// if start level not parsed yet OR
|
32084
32200
|
// if video not attached AND start fragment already requested OR start frag prefetch not enabled
|
32085
32201
|
// exit loop, as we either need more info (level not parsed) or we need media to be attached to load new fragment
|
32086
|
-
if (levelLastLoaded === null || !media && (this.startFragRequested || !hls.config.startFragPrefetch)) {
|
32202
|
+
if (levelLastLoaded === null || !media && !this.primaryPrefetch && (this.startFragRequested || !hls.config.startFragPrefetch)) {
|
32087
32203
|
return;
|
32088
32204
|
}
|
32089
32205
|
|
@@ -32713,11 +32829,11 @@ class StreamController extends BaseStreamController {
|
|
32713
32829
|
}
|
32714
32830
|
|
32715
32831
|
// Offset start position by timeline offset
|
32716
|
-
const
|
32717
|
-
|
32718
|
-
|
32719
|
-
startPosition += (details == null ? void 0 : details.appliedTimelineOffset) || configuredTimelineOffset;
|
32832
|
+
const timelineOffset = this.timelineOffset;
|
32833
|
+
if (timelineOffset && startPosition) {
|
32834
|
+
startPosition += timelineOffset;
|
32720
32835
|
}
|
32836
|
+
const details = this.getLevelDetails();
|
32721
32837
|
const buffered = BufferHelper.getBuffered(media);
|
32722
32838
|
const bufferStart = buffered.length ? buffered.start(0) : 0;
|
32723
32839
|
const delta = bufferStart - startPosition;
|