diff --git a/src/master-playlist-controller.js b/src/master-playlist-controller.js index ca2ef5560..e82bad24c 100644 --- a/src/master-playlist-controller.js +++ b/src/master-playlist-controller.js @@ -301,10 +301,22 @@ export class MasterPlaylistController extends videojs.EventTarget { const nextPlaylist = this.selectPlaylist(); if (this.shouldSwitchToMedia_(nextPlaylist)) { - this.masterPlaylistLoader_.media(nextPlaylist); + this.switchMedia_(nextPlaylist, 'abr'); } } + switchMedia_(playlist, cause, delay) { + const oldMedia = this.media(); + const oldId = oldMedia && (oldMedia.id || oldMedia.uri); + const newId = playlist.id || playlist.uri; + + if (oldId && oldId !== newId) { + this.logger_(`switch media ${oldId} -> ${newId} from ${cause}`); + this.tech_.trigger({type: 'usage', name: `vhs-rendition-change-${cause}`}); + } + this.masterPlaylistLoader_.media(playlist, delay); + } + /** * Start a timer that periodically calls checkABR_ * @@ -416,7 +428,7 @@ export class MasterPlaylistController extends videojs.EventTarget { this.initialMedia_ = selectedMedia; - this.masterPlaylistLoader_.media(this.initialMedia_); + this.switchMedia_(this.initialMedia_, 'initial'); // Under the standard case where a source URL is provided, loadedplaylist will // fire again since the playlist will be requested. In the case of vhs-json @@ -617,7 +629,7 @@ export class MasterPlaylistController extends videojs.EventTarget { const nextPlaylist = this.selectPlaylist(); if (this.shouldSwitchToMedia_(nextPlaylist)) { - this.masterPlaylistLoader_.media(nextPlaylist); + this.switchMedia_(nextPlaylist, 'bandwidthupdate'); } this.tech_.trigger('bandwidthupdate'); @@ -743,7 +755,7 @@ export class MasterPlaylistController extends videojs.EventTarget { return; } - this.masterPlaylistLoader_.media(media); + this.switchMedia_(media, 'smooth-quality'); this.mainSegmentLoader_.resetLoader(); // don't need to reset audio as it is reset when media changes @@ -763,7 +775,7 @@ export class MasterPlaylistController extends videojs.EventTarget { return; } - this.masterPlaylistLoader_.media(media); + this.switchMedia_(media, 'fast-quality'); // Delete all buffered data to allow an immediate quality switch, then seek to give // the browser a kick to remove any cached frames from the previous rendtion (.04 seconds @@ -1118,7 +1130,7 @@ export class MasterPlaylistController extends videojs.EventTarget { (Date.now() - nextPlaylist.lastRequest) <= delayDuration; // delay if it's a final rendition or if the last refresh is sooner than half targetDuration - return this.masterPlaylistLoader_.media(nextPlaylist, isFinalRendition || shouldDelay); + return this.switchMedia_(nextPlaylist, 'exclude', isFinalRendition || shouldDelay); } /** diff --git a/test/master-playlist-controller.test.js b/test/master-playlist-controller.test.js index 54bc35677..dd5a92e70 100644 --- a/test/master-playlist-controller.test.js +++ b/test/master-playlist-controller.test.js @@ -1948,7 +1948,7 @@ QUnit.test('does not get stuck in a loop due to inconsistent network/caching', f const origMedia = playlistLoader.media.bind(playlistLoader); const mediaChanges = []; - mpc.masterPlaylistLoader_.media = (media) => { + mpc.switchMedia_ = (media) => { if (media) { mediaChanges.push(media); } diff --git a/test/playback-watcher.test.js b/test/playback-watcher.test.js index 9b716b3bf..a60f34f57 100644 --- a/test/playback-watcher.test.js +++ b/test/playback-watcher.test.js @@ -1205,6 +1205,7 @@ loaderTypes.forEach(function(type) { expectedUsage['vhs-rendition-blacklisted'] = 1; expectedUsage['hls-rendition-blacklisted'] = 1; + // expectedUsage['vhs-rendition-change-exclude'] = 1; assert.deepEqual(this.usageEvents, expectedUsage, 'usage as expected'); @@ -1224,7 +1225,7 @@ loaderTypes.forEach(function(type) { const loader = this.mpc[`${type}SegmentLoader_`]; const playlists = this.mpc.master().playlists; - const excludeAndVerify = () => { + const excludeAndVerify = (last) => { let oldPlaylist; // this test only needs 9 appends, since we do an intial append @@ -1243,6 +1244,9 @@ loaderTypes.forEach(function(type) { expectedUsage[`vhs-${type}-download-exclusion`] = 1; expectedUsage['vhs-rendition-blacklisted'] = 1; expectedUsage['hls-rendition-blacklisted'] = 1; + if (!last) { + expectedUsage['vhs-rendition-change-exclude'] = 1; + } assert.deepEqual(this.usageEvents, expectedUsage, 'usage as expected'); this.usageEvents = {}; @@ -1283,7 +1287,7 @@ loaderTypes.forEach(function(type) { // exclude all playlists and verify while (i--) { - excludeAndVerify(); + excludeAndVerify((i === 0)); } }); diff --git a/test/videojs-http-streaming.test.js b/test/videojs-http-streaming.test.js index cccfab41e..e1f7ff1bd 100644 --- a/test/videojs-http-streaming.test.js +++ b/test/videojs-http-streaming.test.js @@ -1940,7 +1940,9 @@ QUnit.test('blacklists fmp4 playlists by browser support', function(assert) { assert.strictEqual(typeof playlists[2].excludeUntil, 'undefined', 'did not blacklist second playlist'); assert.deepEqual(debugLogs, [ `Internal problem encountered with playlist ${playlists[0].id}. browser does not support codec(s): "hvc1". Switching to playlist ${playlists[1].id}.`, - `Internal problem encountered with playlist ${playlists[1].id}. browser does not support codec(s): "ac-3". Switching to playlist ${playlists[2].id}.` + `switch media ${playlists[0].id} -> ${playlists[1].id} from exclude`, + `Internal problem encountered with playlist ${playlists[1].id}. browser does not support codec(s): "ac-3". Switching to playlist ${playlists[2].id}.`, + `switch media ${playlists[1].id} -> ${playlists[2].id} from exclude` ], 'debug log as expected'); window.MediaSource.isTypeSupported = oldIsTypeSupported; @@ -2011,7 +2013,9 @@ QUnit.test('blacklists ts playlists by muxer support', function(assert) { assert.strictEqual(typeof playlists[2].excludeUntil, 'undefined', 'did not blacklist third playlist'); assert.deepEqual(debugLogs, [ `Internal problem encountered with playlist ${playlists[0].id}. muxer does not support codec(s): "hvc1". Switching to playlist ${playlists[1].id}.`, - `Internal problem encountered with playlist ${playlists[1].id}. muxer does not support codec(s): "ac-3". Switching to playlist ${playlists[2].id}.` + `switch media ${playlists[0].id} -> ${playlists[1].id} from exclude`, + `Internal problem encountered with playlist ${playlists[1].id}. muxer does not support codec(s): "ac-3". Switching to playlist ${playlists[2].id}.`, + `switch media ${playlists[1].id} -> ${playlists[2].id} from exclude` ], 'debug log as expected'); window.MediaSource.isTypeSupported = oldIsTypeSupported;