From 4e60ef78f6f700676a8ff37b802b86492b2f1454 Mon Sep 17 00:00:00 2001 From: Rob Walch Date: Mon, 7 Oct 2024 21:17:07 -0700 Subject: [PATCH] Fix content-steering when starting with a single pathway and cloning another without a pathway change Fixes #6759 --- src/controller/content-steering-controller.ts | 3 +- .../controller/content-steering-controller.ts | 101 ++++++++++++++++++ 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/src/controller/content-steering-controller.ts b/src/controller/content-steering-controller.ts index 6289bbb6b5b..ece7b5ba8b7 100644 --- a/src/controller/content-steering-controller.ts +++ b/src/controller/content-steering-controller.ts @@ -232,9 +232,8 @@ export default class ContentSteeringController implements NetworkComponentAPI { this.log( `Found ${pathwayLevels.length}/${levels.length} levels in Pathway "${this.pathwayId}"`, ); - return pathwayLevels; } - return levels; + return pathwayLevels; } private getLevelsForPathway(pathwayId: string): Level[] { diff --git a/tests/unit/controller/content-steering-controller.ts b/tests/unit/controller/content-steering-controller.ts index 69292d38ce4..af77d21a301 100644 --- a/tests/unit/controller/content-steering-controller.ts +++ b/tests/unit/controller/content-steering-controller.ts @@ -194,6 +194,107 @@ describe('ContentSteeringController', function () { }); }); + describe('Issue 6759', function () { + const multivariantPlaylist = `#EXTM3U +#EXT-X-CONTENT-STEERING:SERVER-URI="http://example.com/manifest.json",PATHWAY-ID="." +#EXT-X-STREAM-INF:BANDWIDTH=200000,RESOLUTION=720x480,AUDIO="aac" +http://a.example.com/lo/prog_index.m3u8 +#EXT-X-STREAM-INF:BANDWIDTH=500000,RESOLUTION=1920x1080 +http://a.example.com/md/prog_index.m3u8`; + it('clones the Base Pathway without copying FAILBACK variants into hls.levels', function () { + const parsedMultivariant = M3U8Parser.parseMasterPlaylist( + multivariantPlaylist, + 'http://example.com/main.m3u8', + ); + const parsedMediaOptions = M3U8Parser.parseMasterPlaylistMedia( + multivariantPlaylist, + 'http://example.com/main.m3u8', + parsedMultivariant, + ); + const manifestLoadedData = { + contentSteering: parsedMultivariant.contentSteering, + levels: parsedMultivariant.levels, + audioTracks: parsedMediaOptions.AUDIO, + subtitles: parsedMediaOptions.SUBTITLES, + }; + const levelController: any = (hls.levelController = new LevelController( + hls as any, + contentSteeringController as any, + )); + + hls.nextAutoLevel = 0; + contentSteeringController.onManifestLoaded( + Events.MANIFEST_LOADED, + manifestLoadedData, + ); + levelController.onManifestLoaded( + Events.MANIFEST_LOADED, + manifestLoadedData, + ); + + expect( + contentSteeringController.levels, + 'Content Steering variants', + ).to.have.lengthOf(2); + + loadSteeringManifest( + { + VERSION: 1, + TTL: 72000, + 'PATHWAY-PRIORITY': ['.', 'FAILBACK'], + 'PATHWAY-CLONES': [ + { + ID: 'FAILBACK', + 'BASE-ID': '.', + 'URI-REPLACEMENT': { + HOST: 'failback.example.org', + }, + }, + ], + }, + contentSteeringController, + ); + expect( + contentSteeringController.levels, + 'Content Steering variants', + ).to.have.lengthOf(4); + expect(hls.trigger.callCount).to.eq(2); + expect(hls.getEventData(1).name).to.equal( + Events.STEERING_MANIFEST_LOADED, + ); + const steeringManifestLoadedEvent = hls.getEventData(1); + expect(steeringManifestLoadedEvent.payload).to.have.property('url'); + expect(steeringManifestLoadedEvent.payload).to.have.property( + 'steeringManifest', + ); + expect(levelController.levels[0].uri).to.equal( + 'http://a.example.com/lo/prog_index.m3u8', + ); + expect(levelController.levels[1].uri).to.equal( + 'http://a.example.com/md/prog_index.m3u8', + ); + expect(levelController.levels, 'LevelController levels').to.have.lengthOf( + 2, + ); + loadSteeringManifest( + { + 'PATHWAY-PRIORITY': ['FAILBACK'], + }, + contentSteeringController, + ); + expect(hls.trigger.callCount).to.eq(5); + expect(levelController.levels, 'LevelController levels').to.have.lengthOf( + 2, + ); + expect(levelController.levels[0].uri).to.equal( + 'http://failback.example.org/lo/prog_index.m3u8', + ); + expect(levelController.levels[1].uri).to.equal( + 'http://failback.example.org/md/prog_index.m3u8', + ); + }); + }); + describe('Pathway Gouping', function () { let levelController; let audioTrackController;