diff --git a/api-extractor/report/hls.js.api.md b/api-extractor/report/hls.js.api.md index a6a7d4a6c2f..c7db90a66a8 100644 --- a/api-extractor/report/hls.js.api.md +++ b/api-extractor/report/hls.js.api.md @@ -808,6 +808,11 @@ export class ContentSteeringController implements NetworkComponentAPI { // (undocumented) filterParsedLevels(levels: Level[]): Level[]; // (undocumented) + get pathwayPriority(): string[] | null; + set pathwayPriority(pathwayPriority: string[]); + // (undocumented) + pathways(): string[]; + // (undocumented) removeLevel(levelToRemove: Level): void; // (undocumented) startLoad(): void; @@ -1637,6 +1642,10 @@ class Hls implements HlsEventEmitter { on(event: E, listener: HlsListeners[E], context?: Context): void; // (undocumented) once(event: E, listener: HlsListeners[E], context?: Context): void; + get pathwayPriority(): string[] | null; + set pathwayPriority(pathwayPriority: string[]); + // (undocumented) + get pathways(): string[]; pauseBuffering(): void; get playingDate(): Date | null; recoverMediaError(): void; diff --git a/package-lock.json b/package-lock.json index 6696ffc0d35..1536b5d358c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -75,7 +75,8 @@ "typescript": "5.3.3", "url-toolkit": "2.2.5", "wrangler": "3.22.4" - } + }, + "version": "1.5.13" }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", @@ -23222,5 +23223,6 @@ "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", "dev": true } - } + }, + "version": "1.5.13" } diff --git a/package.json b/package.json index bbb05fa1097..920d32481ca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hls.js", - "version": "1.5.12", + "version": "1.5.13", "license": "Apache-2.0", "description": "JavaScript HLS client using MediaSourceExtension", "homepage": "https://github.com/video-dev/hls.js", diff --git a/src/controller/content-steering-controller.ts b/src/controller/content-steering-controller.ts index 6289bbb6b5b..5d7f1031f5c 100644 --- a/src/controller/content-steering-controller.ts +++ b/src/controller/content-steering-controller.ts @@ -54,7 +54,7 @@ export default class ContentSteeringController implements NetworkComponentAPI { private loader: Loader | null = null; private uri: string | null = null; private pathwayId: string = '.'; - private pathwayPriority: string[] | null = null; + private _pathwayPriority: string[] | null = null; private timeToLoad: number = 300; private reloadTimer: number = -1; private updated: number = 0; @@ -90,6 +90,23 @@ export default class ContentSteeringController implements NetworkComponentAPI { hls.off(Events.ERROR, this.onError, this); } + pathways() { + return (this.levels || []).reduce((pathways, level) => { + if (pathways.indexOf(level.pathwayId) === -1) { + pathways.push(level.pathwayId); + } + return pathways; + }, [] as string[]); + } + + get pathwayPriority(): string[] | null { + return this._pathwayPriority; + } + + set pathwayPriority(pathwayPriority: string[]) { + this.updatePathwayPriority(pathwayPriority); + } + startLoad() { this.started = true; this.clearTimeout(); @@ -176,7 +193,7 @@ export default class ContentSteeringController implements NetworkComponentAPI { errorAction.flags === ErrorActionFlags.MoveAllAlternatesMatchingHost ) { const levels = this.levels; - let pathwayPriority = this.pathwayPriority; + let pathwayPriority = this._pathwayPriority; let errorPathway = this.pathwayId; if (data.context) { const { groupId, pathwayId, type } = data.context; @@ -191,12 +208,7 @@ export default class ContentSteeringController implements NetworkComponentAPI { } if (!pathwayPriority && levels) { // If PATHWAY-PRIORITY was not provided, list pathways for error handling - pathwayPriority = levels.reduce((pathways, level) => { - if (pathways.indexOf(level.pathwayId) === -1) { - pathways.push(level.pathwayId); - } - return pathways; - }, [] as string[]); + pathwayPriority = this.pathways(); } if (pathwayPriority && pathwayPriority.length > 1) { this.updatePathwayPriority(pathwayPriority); @@ -245,7 +257,7 @@ export default class ContentSteeringController implements NetworkComponentAPI { } private updatePathwayPriority(pathwayPriority: string[]) { - this.pathwayPriority = pathwayPriority; + this._pathwayPriority = pathwayPriority; let levels: Level[] | undefined; // Evaluate if we should remove the pathway from the penalized list diff --git a/src/controller/level-controller.ts b/src/controller/level-controller.ts index 4fe596cf6e0..8d51e768450 100644 --- a/src/controller/level-controller.ts +++ b/src/controller/level-controller.ts @@ -532,6 +532,34 @@ export default class LevelController extends BasePlaylistController { this._startLevel = newLevel; } + get pathways(): string[] { + return this.steering?.pathways() ?? []; + } + + get pathwayPriority(): string[] | null { + if (this.steering) { + return this.steering.pathwayPriority; + } + + return null; + } + + set pathwayPriority(pathwayPriority: string[]) { + if (this.steering) { + const pathwaysList = this.steering.pathways(); + const filteredPathwayPriority = pathwayPriority.filter((pathwayId) => { + return pathwaysList.indexOf(pathwayId) !== -1; + }); + if (pathwayPriority.length < 1) { + this.warn( + `pathwayPriority ${pathwayPriority} should contain at least one pathway from list: ${pathwaysList}`, + ); + return; + } + this.steering.pathwayPriority = filteredPathwayPriority; + } + } + protected onError(event: Events.ERROR, data: ErrorData) { if (data.fatal || !data.context) { return; diff --git a/src/hls.ts b/src/hls.ts index e04e1aa318f..c21ed0491ac 100644 --- a/src/hls.ts +++ b/src/hls.ts @@ -970,6 +970,21 @@ export default class Hls implements HlsEventEmitter { get forceStartLoad(): boolean { return this.streamController.forceStartLoad; } + + get pathways(): string[] { + return this.levelController.pathways; + } + + /** + * ContentSteering pathwayPriority getter/setter + */ + get pathwayPriority(): string[] | null { + return this.levelController.pathwayPriority; + } + + set pathwayPriority(pathwayPriority: string[]) { + this.levelController.pathwayPriority = pathwayPriority; + } } export type {