Skip to content

Commit 88be787

Browse files
committed
Fallback to primary when Interstitial DateRange is removed while playing
Resolves #6765 Resolves regression in dev starting live interstitials from media playlist (no multivariant playlist loaded startup sequence changed)
1 parent 93dfd4f commit 88be787

File tree

4 files changed

+31
-35
lines changed

4 files changed

+31
-35
lines changed

api-extractor/report/hls.js.api.md

-2
Original file line numberDiff line numberDiff line change
@@ -3646,8 +3646,6 @@ export interface ManifestLoadedData {
36463646
// (undocumented)
36473647
contentSteering: ContentSteeringOptions | null;
36483648
// (undocumented)
3649-
isMediaPlaylist?: boolean;
3650-
// (undocumented)
36513649
levels: LevelParsed[];
36523650
// (undocumented)
36533651
networkDetails: any;

src/controller/interstitials-controller.ts

+27-16
Original file line numberDiff line numberDiff line change
@@ -1151,9 +1151,6 @@ MediaSource ${JSON.stringify(attachMediaSourceData)} from ${logFromSource}`,
11511151
this.waitingItem = null;
11521152

11531153
this.bufferedToItem(scheduledItem);
1154-
if (!fromItem) {
1155-
return;
1156-
}
11571154

11581155
this.log(`resuming ${segmentToString(scheduledItem)}`);
11591156

@@ -1169,6 +1166,10 @@ MediaSource ${JSON.stringify(attachMediaSourceData)} from ${logFromSource}`,
11691166
this.attachPrimary(timelinePos, scheduledItem);
11701167
}
11711168

1169+
if (!fromItem) {
1170+
return;
1171+
}
1172+
11721173
const scheduleItems = this.schedule.items;
11731174
if (!scheduleItems) {
11741175
return;
@@ -1434,14 +1435,6 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
14341435
if (removedIds.length) {
14351436
this.log(`Removed events ${removedIds}`);
14361437
}
1437-
if (
1438-
this.isInterstitial(playingItem) &&
1439-
removedIds.includes(playingItem.event.identifier)
1440-
) {
1441-
this.warn(
1442-
`Interstitial "${playingItem.event.identifier}" removed while playing`,
1443-
);
1444-
}
14451438

14461439
this.playerQueue.forEach((player) => {
14471440
if (player.interstitial.appendInPlace) {
@@ -1474,15 +1467,15 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
14741467
} else if (!this.updateItem(bufferingItem)) {
14751468
// Interstitial removed from schedule (Live -> VOD or other scenario where Start Date is outside the range of VOD Playlist)
14761469
this.bufferingItem = null;
1477-
this.clearInterstitial(bufferingItem.event);
1470+
this.clearInterstitial(bufferingItem.event, null);
14781471
}
14791472
}
14801473
// Clear waitingItem if it has been removed from the schedule
14811474
this.waitingItem = this.updateItem(this.waitingItem);
14821475

14831476
removedInterstitials.forEach((interstitial) => {
14841477
interstitial.assetList.forEach((asset) => {
1485-
this.clearAssetPlayer(asset.identifier);
1478+
this.clearAssetPlayer(asset.identifier, null);
14861479
});
14871480
});
14881481

@@ -1494,6 +1487,17 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
14941487
removedIds,
14951488
});
14961489

1490+
if (
1491+
this.isInterstitial(playingItem) &&
1492+
removedIds.includes(playingItem.event.identifier)
1493+
) {
1494+
this.warn(
1495+
`Interstitial "${playingItem.event.identifier}" removed while playing`,
1496+
);
1497+
this.primaryFallback(playingItem.event);
1498+
return;
1499+
}
1500+
14971501
// Check is buffered to new Interstitial event boundary
14981502
// (Live update publishes Interstitial with new segment)
14991503
this.checkBuffer();
@@ -2065,7 +2069,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
20652069

20662070
private clearInterstitial(
20672071
interstitial: InterstitialEvent,
2068-
toSegment?: InterstitialScheduleItem | null,
2072+
toSegment: InterstitialScheduleItem | null,
20692073
) {
20702074
interstitial.assetList.forEach((asset) => {
20712075
this.clearAssetPlayer(asset.identifier, toSegment);
@@ -2075,7 +2079,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
20752079

20762080
private clearAssetPlayer(
20772081
assetId: InterstitialAssetId,
2078-
toSegment?: InterstitialScheduleItem | null,
2082+
toSegment: InterstitialScheduleItem | null,
20792083
) {
20802084
if (toSegment === null) {
20812085
return;
@@ -2228,7 +2232,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
22282232
const error = new Error(errorMessage);
22292233
if (assetItem) {
22302234
if (this.playingAsset !== assetItem) {
2231-
this.clearAssetPlayer(assetItem.identifier);
2235+
this.clearAssetPlayer(assetItem.identifier, null);
22322236
}
22332237
assetItem.error = error;
22342238
}
@@ -2251,6 +2255,13 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
22512255
// Update schedule now that interstitial/assets are flagged with `error` for fallback
22522256
this.updateSchedule();
22532257
if (playingItem) {
2258+
this.log(
2259+
`Fallback to primary from event "${interstitial.identifier}" start: ${
2260+
flushStart
2261+
} pos: ${this.timelinePos} playing: ${
2262+
playingItem ? segmentToString(playingItem) : '<none>'
2263+
} error: ${interstitial.error}`,
2264+
);
22542265
if (interstitial.appendInPlace) {
22552266
interstitial.appendInPlace = false;
22562267
this.attachPrimary(flushStart, null);

src/loader/playlist-loader.ts

+4-16
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { ErrorDetails, ErrorTypes } from '../errors';
1111
import { Events } from '../events';
1212
import { PlaylistContextType, PlaylistLevelType } from '../types/loader';
1313
import { AttrList } from '../utils/attr-list';
14+
import { computeReloadInterval } from '../utils/level-helper';
1415
import type { LevelDetails } from './level-details';
1516
import type { LoaderConfig, RetryConfig } from '../config';
1617
import type Hls from '../hls';
@@ -19,7 +20,6 @@ import type {
1920
ErrorData,
2021
LevelLoadingData,
2122
LevelsUpdatedData,
22-
ManifestLoadedData,
2323
ManifestLoadingData,
2424
TrackLoadingData,
2525
} from '../types/events';
@@ -70,6 +70,7 @@ class PlaylistLoader implements NetworkComponentAPI {
7070
[key: string]: Loader<LoaderContext>;
7171
} = Object.create(null);
7272
private variableList: VariableMap | null = null;
73+
public onManifestLoaded = this.checkAutostartLoad;
7374

7475
constructor(hls: Hls) {
7576
this.hls = hls;
@@ -498,12 +499,6 @@ class PlaylistLoader implements NetworkComponentAPI {
498499
});
499500
}
500501

501-
onManifestLoaded(event: Events.MANIFEST_LOADED, data: ManifestLoadedData) {
502-
if (!data.isMediaPlaylist) {
503-
this.checkAutostartLoad();
504-
}
505-
}
506-
507502
private handleTrackOrLevelPlaylist(
508503
response: LoaderResponse,
509504
stats: LoaderStats,
@@ -542,6 +537,8 @@ class PlaylistLoader implements NetworkComponentAPI {
542537
name: '',
543538
url,
544539
};
540+
levelDetails.requestScheduled =
541+
stats.loading.start + computeReloadInterval(levelDetails, 0);
545542

546543
hls.trigger(Events.MANIFEST_LOADED, {
547544
levels: [singleLevel],
@@ -554,7 +551,6 @@ class PlaylistLoader implements NetworkComponentAPI {
554551
contentSteering: null,
555552
startTimeOffset: null,
556553
variableList: null,
557-
isMediaPlaylist: true,
558554
});
559555
}
560556

@@ -572,14 +568,6 @@ class PlaylistLoader implements NetworkComponentAPI {
572568
networkDetails,
573569
loader,
574570
);
575-
576-
if (
577-
type === PlaylistContextType.MANIFEST &&
578-
(!levelDetails.playlistParsingError ||
579-
(!levelDetails.fragments.length && levelDetails.live))
580-
) {
581-
this.checkAutostartLoad();
582-
}
583571
}
584572

585573
private handleManifestParsingError(

src/types/events.ts

-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,6 @@ export interface ManifestLoadedData {
138138
subtitles?: MediaPlaylist[];
139139
url: string;
140140
variableList: VariableMap | null;
141-
isMediaPlaylist?: boolean;
142141
}
143142

144143
export interface ManifestParsedData {

0 commit comments

Comments
 (0)