From a7eaf35609da54f224d04e60bab291dc1568bb7c Mon Sep 17 00:00:00 2001 From: Pascal Date: Thu, 21 May 2026 17:59:16 +0200 Subject: [PATCH] Do not lower measured bandwidth with network information --- README.md | 2 +- src/videojs-http-streaming.js | 8 ++++- test/videojs-http-streaming.test.js | 54 +++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 88dee8b06..70ee55508 100644 --- a/README.md +++ b/README.md @@ -491,7 +491,7 @@ This option defaults to `false`. ##### useNetworkInformationApi * Type: `boolean`, * Default: `true` -* Use [window.networkInformation.downlink](https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlink) to estimate the network's bandwidth. Per mdn, _The value is never greater than 10 Mbps, as a non-standard anti-fingerprinting measure_. Given this, if bandwidth estimates from both the player and networkInfo are >= 10 Mbps, the player will use the larger of the two values as its bandwidth estimate. +* Use [window.networkInformation.downlink](https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlink) to estimate the network's bandwidth. Per mdn, _The value is never greater than 10 Mbps, as a non-standard anti-fingerprinting measure_. Given this, before media segment stats are available, if bandwidth estimates from both the player and networkInfo are >= 10 Mbps, the player will use the larger of the two values as its bandwidth estimate. Once media segment stats are available, the player uses the larger of the player estimate and the networkInfo estimate so networkInfo does not lower a player-specific bandwidth estimate. ##### useDtsForTimestampOffset * Type: `boolean`, diff --git a/src/videojs-http-streaming.js b/src/videojs-http-streaming.js index 21dfe7aad..85843bf78 100644 --- a/src/videojs-http-streaming.js +++ b/src/videojs-http-streaming.js @@ -873,16 +873,22 @@ class VhsHandler extends Component { }, bandwidth: { get() { - let playerBandwidthEst = this.playlistController_.mainSegmentLoader_.bandwidth; + const mainSegmentLoader = this.playlistController_.mainSegmentLoader_; + let playerBandwidthEst = mainSegmentLoader.bandwidth; const networkInformation = window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection; const tenMbpsAsBitsPerSecond = 10e6; + const hasSegmentBandwidthEstimate = !isNaN(mainSegmentLoader.roundTrip); if (this.options_.useNetworkInformationApi && networkInformation) { // downlink returns Mbps // https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlink const networkInfoBandwidthEstBitsPerSec = networkInformation.downlink * 1000 * 1000; + if (hasSegmentBandwidthEstimate) { + return Math.max(playerBandwidthEst, networkInfoBandwidthEstBitsPerSec); + } + // downlink maxes out at 10 Mbps. In the event that both networkInformationApi and the player // estimate a bandwidth greater than 10 Mbps, use the larger of the two estimates to ensure that // high quality streams are not filtered out. diff --git a/test/videojs-http-streaming.test.js b/test/videojs-http-streaming.test.js index 65d860b09..a0d3b54b4 100644 --- a/test/videojs-http-streaming.test.js +++ b/test/videojs-http-streaming.test.js @@ -1095,6 +1095,60 @@ QUnit.module('NetworkInformationApi', hooks => { } ); + QUnit.test( + 'bandwidth does not use network-information-api to lower bandwidth after media segment stats are available', + function(assert) { + this.resetNavigatorConnection({ + downlink: 1.5 + }); + this.player = createPlayer({ html5: { vhs: { useNetworkInformationApi: true } } }); + this.player.src({ + src: 'manifest/main.m3u8', + type: 'application/vnd.apple.mpegurl' + }); + + this.clock.tick(1); + + const mainSegmentLoader = this.player.tech_.vhs.playlistController_.mainSegmentLoader_; + + mainSegmentLoader.bandwidth = 20e6; + mainSegmentLoader.roundTrip = 100; + + assert.strictEqual( + this.player.tech_.vhs.bandwidth, + 20e6, + 'bandwidth getter returned the higher player-estimated bandwidth value after media segment stats' + ); + } + ); + + QUnit.test( + 'bandwidth can use network-information-api to raise bandwidth after media segment stats are available', + function(assert) { + this.resetNavigatorConnection({ + downlink: 9 + }); + this.player = createPlayer({ html5: { vhs: { useNetworkInformationApi: true } } }); + this.player.src({ + src: 'manifest/main.m3u8', + type: 'application/vnd.apple.mpegurl' + }); + + this.clock.tick(1); + + const mainSegmentLoader = this.player.tech_.vhs.playlistController_.mainSegmentLoader_; + + mainSegmentLoader.bandwidth = 2e6; + mainSegmentLoader.roundTrip = 100; + + assert.strictEqual( + this.player.tech_.vhs.bandwidth, + 9e6, + 'bandwidth getter returned the higher network-information-api bandwidth value after media segment stats' + ); + } + ); + QUnit.test( 'bandwidth uses player-estimated bandwidth when networkInformation is not supported', function(assert) {