hls.js 1.6.3-0.canary.11251 → 1.6.3-0.canary.11253
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 +3 -0
- package/dist/hls.d.ts +3 -0
- package/dist/hls.js +84 -41
- package/dist/hls.js.d.ts +3 -0
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +4 -3
- 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 +4 -3
- 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 +80 -39
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/package.json +1 -1
- package/src/config.ts +2 -0
- package/src/controller/error-controller.ts +1 -1
- package/src/controller/interstitial-player.ts +12 -0
- package/src/controller/interstitials-controller.ts +69 -51
- package/src/loader/interstitial-event.ts +15 -2
@@ -15,6 +15,7 @@ import {
|
|
15
15
|
ALIGNED_END_THRESHOLD_SECONDS,
|
16
16
|
eventAssetToString,
|
17
17
|
generateAssetIdentifier,
|
18
|
+
getNextAssetIndex,
|
18
19
|
type InterstitialAssetId,
|
19
20
|
type InterstitialAssetItem,
|
20
21
|
type InterstitialEvent,
|
@@ -1008,11 +1009,8 @@ export default class InterstitialsController
|
|
1008
1009
|
index: number,
|
1009
1010
|
assetListIndex: number,
|
1010
1011
|
) {
|
1011
|
-
const nextAssetIndex = assetListIndex
|
1012
|
-
if (
|
1013
|
-
!interstitial.isAssetPastPlayoutLimit(nextAssetIndex) &&
|
1014
|
-
!interstitial.assetList[nextAssetIndex].error
|
1015
|
-
) {
|
1012
|
+
const nextAssetIndex = getNextAssetIndex(interstitial, assetListIndex);
|
1013
|
+
if (!interstitial.isAssetPastPlayoutLimit(nextAssetIndex)) {
|
1016
1014
|
// Advance to next asset list item
|
1017
1015
|
this.setSchedulePosition(index, nextAssetIndex);
|
1018
1016
|
} else {
|
@@ -1046,7 +1044,7 @@ export default class InterstitialsController
|
|
1046
1044
|
if (interstitial) {
|
1047
1045
|
const itemIndex = schedule.findEventIndex(parentIdentifier);
|
1048
1046
|
const assetListIndex = schedule.findAssetIndex(interstitial, time);
|
1049
|
-
this.
|
1047
|
+
this.advanceAfterAssetEnded(interstitial, itemIndex, assetListIndex - 1);
|
1050
1048
|
}
|
1051
1049
|
}
|
1052
1050
|
|
@@ -1072,15 +1070,15 @@ export default class InterstitialsController
|
|
1072
1070
|
(assetListIndex !== undefined &&
|
1073
1071
|
assetId !== interstitial.assetList?.[assetListIndex].identifier))
|
1074
1072
|
) {
|
1075
|
-
const
|
1073
|
+
const playingAssetListIndex = interstitial.findAssetIndex(playingAsset);
|
1076
1074
|
this.log(
|
1077
|
-
`INTERSTITIAL_ASSET_ENDED ${
|
1075
|
+
`INTERSTITIAL_ASSET_ENDED ${playingAssetListIndex + 1}/${interstitial.assetList.length} ${eventAssetToString(playingAsset)}`,
|
1078
1076
|
);
|
1079
1077
|
this.endedAsset = playingAsset;
|
1080
1078
|
this.playingAsset = null;
|
1081
1079
|
this.hls.trigger(Events.INTERSTITIAL_ASSET_ENDED, {
|
1082
1080
|
asset: playingAsset,
|
1083
|
-
assetListIndex,
|
1081
|
+
assetListIndex: playingAssetListIndex,
|
1084
1082
|
event: interstitial,
|
1085
1083
|
schedule: scheduleItems.slice(0),
|
1086
1084
|
scheduleIndex: index,
|
@@ -1166,6 +1164,15 @@ export default class InterstitialsController
|
|
1166
1164
|
interstitial,
|
1167
1165
|
this.timelinePos,
|
1168
1166
|
);
|
1167
|
+
const assetIndexCandidate = getNextAssetIndex(
|
1168
|
+
interstitial,
|
1169
|
+
assetListIndex - 1,
|
1170
|
+
);
|
1171
|
+
if (interstitial.isAssetPastPlayoutLimit(assetIndexCandidate)) {
|
1172
|
+
this.advanceAfterAssetEnded(interstitial, index, assetListIndex);
|
1173
|
+
return;
|
1174
|
+
}
|
1175
|
+
assetListIndex = assetIndexCandidate;
|
1169
1176
|
}
|
1170
1177
|
// Ensure Interstitial is enqueued
|
1171
1178
|
const waitingItem = this.waitingItem;
|
@@ -1315,7 +1322,7 @@ export default class InterstitialsController
|
|
1315
1322
|
if (!scheduleItems) {
|
1316
1323
|
return;
|
1317
1324
|
}
|
1318
|
-
this.log(`
|
1325
|
+
this.log(`INTERSTITIALS_PRIMARY_RESUMED ${segmentToString(scheduledItem)}`);
|
1319
1326
|
this.hls.trigger(Events.INTERSTITIALS_PRIMARY_RESUMED, {
|
1320
1327
|
schedule: scheduleItems.slice(0),
|
1321
1328
|
scheduleIndex: index,
|
@@ -1577,7 +1584,7 @@ export default class InterstitialsController
|
|
1577
1584
|
const interstitialsUpdated = !!(
|
1578
1585
|
interstitialEvents.length || removedIds.length
|
1579
1586
|
);
|
1580
|
-
if (interstitialsUpdated) {
|
1587
|
+
if (interstitialsUpdated || previousItems) {
|
1581
1588
|
this.log(
|
1582
1589
|
`INTERSTITIALS_UPDATED (${
|
1583
1590
|
interstitialEvents.length
|
@@ -1874,16 +1881,16 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
1874
1881
|
item.start,
|
1875
1882
|
Math.min(item.end, this.timelinePos),
|
1876
1883
|
);
|
1884
|
+
const timeRemaining = bufferingPlayer
|
1885
|
+
? bufferingPlayer.remaining
|
1886
|
+
: bufferingLast
|
1887
|
+
? bufferingLast.end - this.timelinePos
|
1888
|
+
: 0;
|
1889
|
+
this.log(
|
1890
|
+
`INTERSTITIALS_BUFFERED_TO_BOUNDARY ${segmentToString(item)}` +
|
1891
|
+
(bufferingLast ? ` (${timeRemaining.toFixed(2)} remaining)` : ''),
|
1892
|
+
);
|
1877
1893
|
if (!this.playbackDisabled) {
|
1878
|
-
const timeRemaining = bufferingPlayer
|
1879
|
-
? bufferingPlayer.remaining
|
1880
|
-
: bufferingLast
|
1881
|
-
? bufferingLast.end - this.timelinePos
|
1882
|
-
: 0;
|
1883
|
-
this.log(
|
1884
|
-
`buffered to boundary ${segmentToString(item)}` +
|
1885
|
-
(bufferingLast ? ` (${timeRemaining.toFixed(2)} remaining)` : ''),
|
1886
|
-
);
|
1887
1894
|
if (isInterstitial) {
|
1888
1895
|
// primary fragment loading will exit early in base-stream-controller while `bufferingItem` is set to an Interstitial block
|
1889
1896
|
item.event.assetList.forEach((asset) => {
|
@@ -2114,7 +2121,6 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
2114
2121
|
assetItem: InterstitialAssetItem,
|
2115
2122
|
assetListIndex: number,
|
2116
2123
|
): HlsAssetPlayer {
|
2117
|
-
this.log(`create HLSAssetPlayer for ${eventAssetToString(assetItem)}`);
|
2118
2124
|
const primary = this.hls;
|
2119
2125
|
const userConfig = primary.userConfig;
|
2120
2126
|
let videoPreference = userConfig.videoPreference;
|
@@ -2250,15 +2256,11 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
2250
2256
|
const scheduleIndex = this.schedule.findEventIndex(
|
2251
2257
|
interstitial.identifier,
|
2252
2258
|
);
|
2253
|
-
const assetListIndex = interstitial.findAssetIndex(assetItem);
|
2254
|
-
const nextAssetIndex = assetListIndex + 1;
|
2255
2259
|
const item = this.schedule.items?.[scheduleIndex];
|
2256
2260
|
if (this.isInterstitial(item)) {
|
2257
|
-
|
2258
|
-
|
2259
|
-
|
2260
|
-
!interstitial.assetList[nextAssetIndex].error
|
2261
|
-
) {
|
2261
|
+
const assetListIndex = interstitial.findAssetIndex(assetItem);
|
2262
|
+
const nextAssetIndex = getNextAssetIndex(interstitial, assetListIndex);
|
2263
|
+
if (!interstitial.isAssetPastPlayoutLimit(nextAssetIndex)) {
|
2262
2264
|
this.bufferedToItem(item, nextAssetIndex);
|
2263
2265
|
} else {
|
2264
2266
|
const nextItem = this.schedule.items?.[scheduleIndex + 1];
|
@@ -2337,7 +2339,9 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
2337
2339
|
error.message,
|
2338
2340
|
);
|
2339
2341
|
});
|
2340
|
-
|
2342
|
+
this.log(
|
2343
|
+
`INTERSTITIAL_ASSET_PLAYER_CREATED ${eventAssetToString(assetItem)}`,
|
2344
|
+
);
|
2341
2345
|
this.hls.trigger(Events.INTERSTITIAL_ASSET_PLAYER_CREATED, {
|
2342
2346
|
asset: assetItem,
|
2343
2347
|
assetListIndex,
|
@@ -2358,6 +2362,17 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
2358
2362
|
interstitial.reset();
|
2359
2363
|
}
|
2360
2364
|
|
2365
|
+
private resetAssetPlayer(assetId: InterstitialAssetId) {
|
2366
|
+
// Reset asset player so that it's timeline can be adjusted without reloading the MVP
|
2367
|
+
const playerIndex = this.getAssetPlayerQueueIndex(assetId);
|
2368
|
+
if (playerIndex !== -1) {
|
2369
|
+
this.log(`reset asset player "${assetId}" after error`);
|
2370
|
+
const player = this.playerQueue[playerIndex];
|
2371
|
+
this.transferMediaFromPlayer(player, null);
|
2372
|
+
player.resetDetails();
|
2373
|
+
}
|
2374
|
+
}
|
2375
|
+
|
2361
2376
|
private clearAssetPlayer(
|
2362
2377
|
assetId: InterstitialAssetId,
|
2363
2378
|
toSegment: InterstitialScheduleItem | null,
|
@@ -2365,7 +2380,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
2365
2380
|
const playerIndex = this.getAssetPlayerQueueIndex(assetId);
|
2366
2381
|
if (playerIndex !== -1) {
|
2367
2382
|
this.log(
|
2368
|
-
`
|
2383
|
+
`clear asset player "${assetId}" toSegment: ${toSegment ? segmentToString(toSegment) : toSegment}`,
|
2369
2384
|
);
|
2370
2385
|
const player = this.playerQueue[playerIndex];
|
2371
2386
|
this.transferMediaFromPlayer(player, toSegment);
|
@@ -2405,7 +2420,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
2405
2420
|
delete playingAsset.error;
|
2406
2421
|
}
|
2407
2422
|
this.log(
|
2408
|
-
`INTERSTITIAL_ASSET_STARTED ${assetListIndex + 1}/${assetListLength} ${
|
2423
|
+
`INTERSTITIAL_ASSET_STARTED ${assetListIndex + 1}/${assetListLength} ${eventAssetToString(assetItem)}`,
|
2409
2424
|
);
|
2410
2425
|
this.hls.trigger(Events.INTERSTITIAL_ASSET_STARTED, {
|
2411
2426
|
asset: assetItem,
|
@@ -2456,7 +2471,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
2456
2471
|
!isCompatibleTrackChange(activeTracks, player.tracks)
|
2457
2472
|
) {
|
2458
2473
|
const error = new Error(
|
2459
|
-
`Asset
|
2474
|
+
`Asset ${eventAssetToString(assetItem)} SourceBuffer tracks ('${Object.keys(player.tracks)}') are not compatible with primary content tracks ('${Object.keys(activeTracks)}')`,
|
2460
2475
|
);
|
2461
2476
|
const errorData: ErrorData = {
|
2462
2477
|
fatal: true,
|
@@ -2489,13 +2504,13 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
2489
2504
|
if (data.details === ErrorDetails.BUFFER_STALLED_ERROR) {
|
2490
2505
|
return;
|
2491
2506
|
}
|
2492
|
-
|
2493
|
-
|
2494
|
-
|
2495
|
-
|
2496
|
-
|
2497
|
-
|
2498
|
-
|
2507
|
+
const assetItem = interstitial.assetList[assetListIndex];
|
2508
|
+
this.warn(
|
2509
|
+
`INTERSTITIAL_ASSET_ERROR ${assetItem ? eventAssetToString(assetItem) : assetItem} ${data.error}`,
|
2510
|
+
);
|
2511
|
+
const assetId = assetItem?.identifier;
|
2512
|
+
const playerIndex = this.getAssetPlayerQueueIndex(assetId);
|
2513
|
+
const player = this.playerQueue[playerIndex] || null;
|
2499
2514
|
const items = this.schedule.items;
|
2500
2515
|
const interstitialAssetError = Object.assign({}, data, {
|
2501
2516
|
fatal: false,
|
@@ -2507,17 +2522,15 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
2507
2522
|
scheduleIndex,
|
2508
2523
|
player,
|
2509
2524
|
});
|
2510
|
-
this.warn(`Asset item error: ${data.error}`);
|
2511
2525
|
this.hls.trigger(Events.INTERSTITIAL_ASSET_ERROR, interstitialAssetError);
|
2512
2526
|
if (!data.fatal) {
|
2513
2527
|
return;
|
2514
2528
|
}
|
2515
2529
|
|
2530
|
+
const playingAsset = this.playingAsset;
|
2516
2531
|
const error = new Error(errorMessage);
|
2517
2532
|
if (assetItem) {
|
2518
|
-
|
2519
|
-
this.clearAssetPlayer(assetItem.identifier, null);
|
2520
|
-
}
|
2533
|
+
this.clearAssetPlayer(assetId, null);
|
2521
2534
|
assetItem.error = error;
|
2522
2535
|
}
|
2523
2536
|
|
@@ -2525,11 +2538,17 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
2525
2538
|
if (!interstitial.assetList.some((asset) => !asset.error)) {
|
2526
2539
|
interstitial.error = error;
|
2527
2540
|
} else if (interstitial.appendInPlace) {
|
2528
|
-
//
|
2529
|
-
interstitial.
|
2541
|
+
// Reset level details and reload/parse media playlists to align with updated schedule
|
2542
|
+
for (let i = assetListIndex; i < interstitial.assetList.length; i++) {
|
2543
|
+
this.resetAssetPlayer(interstitial.assetList[i].identifier);
|
2544
|
+
}
|
2545
|
+
this.updateSchedule();
|
2546
|
+
}
|
2547
|
+
if (interstitial.error) {
|
2548
|
+
this.primaryFallback(interstitial);
|
2549
|
+
} else if (playingAsset && playingAsset.identifier === assetId) {
|
2550
|
+
this.advanceAfterAssetEnded(interstitial, scheduleIndex, assetListIndex);
|
2530
2551
|
}
|
2531
|
-
|
2532
|
-
this.primaryFallback(interstitial);
|
2533
2552
|
}
|
2534
2553
|
|
2535
2554
|
private primaryFallback(interstitial: InterstitialEvent) {
|
@@ -2551,16 +2570,15 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
2551
2570
|
timelinePos = this.hls.startPosition;
|
2552
2571
|
}
|
2553
2572
|
const newPlayingItem = this.updateItem(playingItem, timelinePos);
|
2554
|
-
if (
|
2555
|
-
const scheduleIndex = this.schedule.findItemIndexAtTime(timelinePos);
|
2556
|
-
this.setSchedulePosition(scheduleIndex);
|
2557
|
-
} else {
|
2573
|
+
if (this.itemsMatch(playingItem, newPlayingItem)) {
|
2558
2574
|
this.clearInterstitial(interstitial, null);
|
2559
2575
|
}
|
2560
2576
|
if (interstitial.appendInPlace) {
|
2561
2577
|
this.attachPrimary(flushStart, null);
|
2562
2578
|
this.flushFrontBuffer(flushStart);
|
2563
2579
|
}
|
2580
|
+
const scheduleIndex = this.schedule.findItemIndexAtTime(timelinePos);
|
2581
|
+
this.setSchedulePosition(scheduleIndex);
|
2564
2582
|
} else {
|
2565
2583
|
this.checkStart();
|
2566
2584
|
}
|
@@ -118,14 +118,17 @@ export class InterstitialEvent {
|
|
118
118
|
}
|
119
119
|
|
120
120
|
public isAssetPastPlayoutLimit(assetIndex: number): boolean {
|
121
|
-
if (assetIndex >= this.assetList.length) {
|
121
|
+
if (assetIndex > 0 && assetIndex >= this.assetList.length) {
|
122
122
|
return true;
|
123
123
|
}
|
124
124
|
const playoutLimit = this.playoutLimit;
|
125
125
|
if (assetIndex <= 0 || isNaN(playoutLimit)) {
|
126
126
|
return false;
|
127
127
|
}
|
128
|
-
|
128
|
+
if (playoutLimit === 0) {
|
129
|
+
return true;
|
130
|
+
}
|
131
|
+
const assetOffset = this.assetList[assetIndex]?.startOffset || 0;
|
129
132
|
return assetOffset > playoutLimit;
|
130
133
|
}
|
131
134
|
|
@@ -313,6 +316,16 @@ export function getInterstitialUrl(
|
|
313
316
|
return url;
|
314
317
|
}
|
315
318
|
|
319
|
+
export function getNextAssetIndex(
|
320
|
+
interstitial: InterstitialEvent,
|
321
|
+
assetListIndex: number,
|
322
|
+
): number {
|
323
|
+
while (interstitial.assetList[++assetListIndex]?.error) {
|
324
|
+
/* no-op */
|
325
|
+
}
|
326
|
+
return assetListIndex;
|
327
|
+
}
|
328
|
+
|
316
329
|
function eventToString(interstitial: InterstitialEvent): string {
|
317
330
|
return `["${interstitial.identifier}" ${interstitial.cue.pre ? '<pre>' : interstitial.cue.post ? '<post>' : ''}${interstitial.timelineStart.toFixed(2)}-${interstitial.resumeTime.toFixed(2)}]`;
|
318
331
|
}
|