From 4c169588c33de43efc5ce78649e45a56bcc4366a Mon Sep 17 00:00:00 2001 From: Evan farina Date: Fri, 29 Oct 2021 15:10:03 -0400 Subject: [PATCH 1/9] Add an option to calculate bandwidth by using Chromium's networkInfo API --- index.html | 5 +++++ scripts/index.js | 5 ++++- src/videojs-http-streaming.js | 25 ++++++++++++++++++++++++- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index ef2d08342..a0b9e7533 100644 --- a/index.html +++ b/index.html @@ -166,6 +166,11 @@ +
+ + +
+
diff --git a/scripts/index.js b/scripts/index.js index 27c314d3f..16464165f 100644 --- a/scripts/index.js +++ b/scripts/index.js @@ -447,6 +447,7 @@ 'buffer-water', 'exact-manifest-timings', 'pixel-diff-selector', + 'network-info', 'override-native', 'preload', 'mirror-source' @@ -499,6 +500,7 @@ 'override-native', 'liveui', 'pixel-diff-selector', + 'network-info', 'exact-manifest-timings' ].forEach(function(name) { stateEls[name].addEventListener('change', function(event) { @@ -565,7 +567,8 @@ experimentalBufferBasedABR: getInputValue(stateEls['buffer-water']), experimentalLLHLS: getInputValue(stateEls.llhls), experimentalExactManifestTimings: getInputValue(stateEls['exact-manifest-timings']), - experimentalLeastPixelDiffSelector: getInputValue(stateEls['pixel-diff-selector']) + experimentalLeastPixelDiffSelector: getInputValue(stateEls['pixel-diff-selector']), + useNetworkInformation: getInputValue(stateEls['network-info']) } } }); diff --git a/src/videojs-http-streaming.js b/src/videojs-http-streaming.js index d5e78284d..359449b09 100644 --- a/src/videojs-http-streaming.js +++ b/src/videojs-http-streaming.js @@ -617,6 +617,18 @@ class VhsHandler extends Component { }); this.on(this.tech_, 'play', this.play); + + if (this.options_.useNetworkInformation) { + this.networkInformation = window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection; + + this.networkInformation.addEventListener('change', () => this.setNetworkInformationStats_()); + + this.setNetworkInformationStats_(); + } + } + + setNetworkInformationStats_() { + this.effectiveBandwidthInBits_ = this.networkInformation.downlink * 1000 * 1000; } setOptions_() { @@ -630,6 +642,7 @@ class VhsHandler extends Component { typeof this.source_.useBandwidthFromLocalStorage !== 'undefined' ? this.source_.useBandwidthFromLocalStorage : this.options_.useBandwidthFromLocalStorage || false; + this.options_.useNetworkInformation = this.options_.useNetworkInformation || false; this.options_.customTagParsers = this.options_.customTagParsers || []; this.options_.customTagMappers = this.options_.customTagMappers || []; this.options_.cacheEncryptionKeys = this.options_.cacheEncryptionKeys || false; @@ -682,6 +695,7 @@ class VhsHandler extends Component { 'experimentalBufferBasedABR', 'liveRangeSafeTimeDelta', 'experimentalLLHLS', + 'useNetworkInformation', 'experimentalExactManifestTimings', 'experimentalLeastPixelDiffSelector' ].forEach((option) => { @@ -813,7 +827,16 @@ class VhsHandler extends Component { */ systemBandwidth: { get() { - const invBandwidth = 1 / (this.bandwidth || 1); + let bandwidthEst = this.bandwidth; + + // NetworkInfo.downlink maxes out at 10Mb/s. In the event that the player estimates a bandwidth + // greater than 10Mb, use the larger value to ensure that high quality streams are not + // accidentally filtered out + if (this.options_.useNetworkInformation) { + bandwidthEst = Math.max(bandwidthEst, this.effectiveBandwidthInBits_); + } + + const invBandwidth = 1 / (bandwidthEst || 1); let invThroughput; if (this.throughput > 0) { From 3c8dd35dbe11c5074fa5d3d3ddc868c529566629 Mon Sep 17 00:00:00 2001 From: Evan farina Date: Fri, 29 Oct 2021 19:11:40 -0400 Subject: [PATCH 2/9] Add guard around networkInformation usage and added tests --- src/videojs-http-streaming.js | 7 ++- test/videojs-http-streaming.test.js | 93 +++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 2 deletions(-) diff --git a/src/videojs-http-streaming.js b/src/videojs-http-streaming.js index 359449b09..6109e59c3 100644 --- a/src/videojs-http-streaming.js +++ b/src/videojs-http-streaming.js @@ -563,6 +563,7 @@ class VhsHandler extends Component { this.source_ = source; this.stats = {}; this.ignoreNextSeekingEvent_ = false; + this.effectiveBandwidthInBits_ = 0; this.setOptions_(); if (this.options_.overrideNative && @@ -621,9 +622,11 @@ class VhsHandler extends Component { if (this.options_.useNetworkInformation) { this.networkInformation = window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection; - this.networkInformation.addEventListener('change', () => this.setNetworkInformationStats_()); + if (this.networkInformation) { + this.networkInformation.addEventListener('change', () => this.setNetworkInformationStats_()); - this.setNetworkInformationStats_(); + this.setNetworkInformationStats_(); + } } } diff --git a/test/videojs-http-streaming.test.js b/test/videojs-http-streaming.test.js index dd552cd90..76d91e4d0 100644 --- a/test/videojs-http-streaming.test.js +++ b/test/videojs-http-streaming.test.js @@ -1160,6 +1160,99 @@ QUnit.test( } ); +QUnit.test( + 'systemBandwidth retrieves bandwidth from networkInformation when option is enabled', + function(assert) { + this.player = createPlayer({ html5: { vhs: { useNetworkInformation: true } } }); + this.player.src({ + src: 'manifest/master.m3u8', + type: 'application/vnd.apple.mpegurl' + }); + + this.clock.tick(1); + + this.player.tech_.vhs.bandwidth = 10e10; + this.player.tech_.vhs.effectiveBandwidthInBits_ = 20e10; + this.player.tech_.vhs.throughput = 20e10; + // 1 / ( 1 / 20e10 + 1 / 20e10) = 10e10 + assert.strictEqual( + this.player.tech_.vhs.systemBandwidth, + 10e10, + 'systemBandwidth is the combination of networkInfo.downlink and throughput' + ); + } +); + +QUnit.test( + 'systemBandwidth uses player-estimated bandwidth when its value is greater than networkInformation.downLink', + function(assert) { + this.player = createPlayer({ html5: { vhs: { useNetworkInformation: true } } }); + this.player.src({ + src: 'manifest/master.m3u8', + type: 'application/vnd.apple.mpegurl' + }); + + this.clock.tick(1); + + this.player.tech_.vhs.bandwidth = 20e10; + this.player.tech_.vhs.effectiveBandwidthInBits_ = 10e10; + this.player.tech_.vhs.throughput = 20e10; + // 1 / ( 1 / 20e10 + 1 / 20e10) = 10e10 + assert.strictEqual( + this.player.tech_.vhs.systemBandwidth, + 10e10, + 'systemBandwidth is the combination of player bandwidth and throughput' + ); + } +); + +QUnit.test( + 'effectiveBandwidthInBits_ default', + function(assert) { + this.player.src({ + src: 'manifest/master.m3u8', + type: 'application/vnd.apple.mpegurl' + }); + + this.clock.tick(1); + + assert.strictEqual( + this.player.tech_.vhs.effectiveBandwidthInBits_, + 0, + 'effectiveBandwidthInBits_ defaults to 0' + ); + } +); + +QUnit.test( + 'systemBandwidth uses player-estimated bandwidth when networkInformation is not supported', + function(assert) { + const ogNavigator = window.navigator; + + // Need to delete the property before setting since navigator doesn't have a setter + delete window.navigator; + window.navigator = {}; + this.player = createPlayer({ html5: { vhs: { useNetworkInformation: true } } }); + this.player.src({ + src: 'manifest/master.m3u8', + type: 'application/vnd.apple.mpegurl' + }); + + this.clock.tick(1); + + this.player.tech_.vhs.bandwidth = 20e10; + this.player.tech_.vhs.throughput = 20e10; + // 1 / ( 1 / 20e10 + 1 / 20e10) = 10e10 + assert.strictEqual( + this.player.tech_.vhs.systemBandwidth, + 10e10, + 'systemBandwidth is the combination of player bandwidth and throughput since networkInformation is not supported' + ); + + window.navigator = ogNavigator; + } +); + QUnit.test('requests a reasonable rendition to start', function(assert) { this.player.src({ src: 'manifest/master.m3u8', From 76c5aa29bfe7083d9042db566f8d9cef867d8b44 Mon Sep 17 00:00:00 2001 From: Evan farina Date: Tue, 2 Nov 2021 10:46:49 -0400 Subject: [PATCH 3/9] Added documentation for networkInformationApi option. Moved networkInfo tests into their own module --- README.md | 6 + index.html | 2 +- src/videojs-http-streaming.js | 28 ++--- test/videojs-http-streaming.test.js | 164 ++++++++++++++-------------- 4 files changed, 100 insertions(+), 100 deletions(-) diff --git a/README.md b/README.md index 27f28ceb4..95850bf5c 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ Video.js Compatibility: 6.0, 7.0 - [cacheEncryptionKeys](#cacheencryptionkeys) - [handlePartialData](#handlepartialdata) - [liveRangeSafeTimeDelta](#liverangesafetimedelta) + - [useNetworkInformationApi](#usenetworkinformationapi) - [captionServices](#captionservices) - [Format](#format) - [Example](#example) @@ -473,6 +474,11 @@ This option defaults to `false`. * Default: [`SAFE_TIME_DELTA`](https://github.com/videojs/http-streaming/blob/e7cb63af010779108336eddb5c8fd138d6390e95/src/ranges.js#L17) * Allow to re-define length (in seconds) of time delta when you compare current time and the end of the buffered range. +##### useNetworkInformationApi +* Type: `boolean`, +* Default: `false` +* Use [window.networkInformation.downlink](https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlink) to estimate the network's bandwidth + ##### captionServices * Type: `object` * Default: undefined diff --git a/index.html b/index.html index a0b9e7533..30fbe10ce 100644 --- a/index.html +++ b/index.html @@ -168,7 +168,7 @@
- +
diff --git a/src/videojs-http-streaming.js b/src/videojs-http-streaming.js index 6109e59c3..a817a9599 100644 --- a/src/videojs-http-streaming.js +++ b/src/videojs-http-streaming.js @@ -563,7 +563,6 @@ class VhsHandler extends Component { this.source_ = source; this.stats = {}; this.ignoreNextSeekingEvent_ = false; - this.effectiveBandwidthInBits_ = 0; this.setOptions_(); if (this.options_.overrideNative && @@ -619,21 +618,11 @@ class VhsHandler extends Component { this.on(this.tech_, 'play', this.play); - if (this.options_.useNetworkInformation) { + if (this.options_.useNetworkInformationApi) { this.networkInformation = window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection; - - if (this.networkInformation) { - this.networkInformation.addEventListener('change', () => this.setNetworkInformationStats_()); - - this.setNetworkInformationStats_(); - } } } - setNetworkInformationStats_() { - this.effectiveBandwidthInBits_ = this.networkInformation.downlink * 1000 * 1000; - } - setOptions_() { // defaults this.options_.withCredentials = this.options_.withCredentials || false; @@ -645,7 +634,7 @@ class VhsHandler extends Component { typeof this.source_.useBandwidthFromLocalStorage !== 'undefined' ? this.source_.useBandwidthFromLocalStorage : this.options_.useBandwidthFromLocalStorage || false; - this.options_.useNetworkInformation = this.options_.useNetworkInformation || false; + this.options_.useNetworkInformationApi = this.options_.useNetworkInformationApi || false; this.options_.customTagParsers = this.options_.customTagParsers || []; this.options_.customTagMappers = this.options_.customTagMappers || []; this.options_.cacheEncryptionKeys = this.options_.cacheEncryptionKeys || false; @@ -698,7 +687,7 @@ class VhsHandler extends Component { 'experimentalBufferBasedABR', 'liveRangeSafeTimeDelta', 'experimentalLLHLS', - 'useNetworkInformation', + 'useNetworkInformationApi', 'experimentalExactManifestTimings', 'experimentalLeastPixelDiffSelector' ].forEach((option) => { @@ -832,11 +821,14 @@ class VhsHandler extends Component { get() { let bandwidthEst = this.bandwidth; - // NetworkInfo.downlink maxes out at 10Mb/s. In the event that the player estimates a bandwidth - // greater than 10Mb, use the larger value to ensure that high quality streams are not + // NetworkInfo.downlink maxes out at 10 Mbps. In the event that the player estimates a bandwidth + // greater than 10 Mbps, use the larger value to ensure that high quality streams are not // accidentally filtered out - if (this.options_.useNetworkInformation) { - bandwidthEst = Math.max(bandwidthEst, this.effectiveBandwidthInBits_); + if (this.options_.useNetworkInformationApi && this.networkInformation) { + // Downlink property returns Mbps https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlink + const effectiveBandwidthBitsPerSec = this.networkInformation.downlink * 1000 * 1000; + + bandwidthEst = Math.max(bandwidthEst, effectiveBandwidthBitsPerSec); } const invBandwidth = 1 / (bandwidthEst || 1); diff --git a/test/videojs-http-streaming.test.js b/test/videojs-http-streaming.test.js index 76d91e4d0..fbb3be6e2 100644 --- a/test/videojs-http-streaming.test.js +++ b/test/videojs-http-streaming.test.js @@ -1160,98 +1160,100 @@ QUnit.test( } ); -QUnit.test( - 'systemBandwidth retrieves bandwidth from networkInformation when option is enabled', - function(assert) { - this.player = createPlayer({ html5: { vhs: { useNetworkInformation: true } } }); - this.player.src({ - src: 'manifest/master.m3u8', - type: 'application/vnd.apple.mpegurl' - }); - - this.clock.tick(1); - - this.player.tech_.vhs.bandwidth = 10e10; - this.player.tech_.vhs.effectiveBandwidthInBits_ = 20e10; - this.player.tech_.vhs.throughput = 20e10; - // 1 / ( 1 / 20e10 + 1 / 20e10) = 10e10 - assert.strictEqual( - this.player.tech_.vhs.systemBandwidth, - 10e10, - 'systemBandwidth is the combination of networkInfo.downlink and throughput' - ); - } -); +QUnit.module('NetworkInformationApi', hooks => { + hooks.beforeEach(function(assert) { + this.env = useFakeEnvironment(assert); + this.ogNavigator = window.navigator; + this.clock = this.env.clock; -QUnit.test( - 'systemBandwidth uses player-estimated bandwidth when its value is greater than networkInformation.downLink', - function(assert) { - this.player = createPlayer({ html5: { vhs: { useNetworkInformation: true } } }); - this.player.src({ - src: 'manifest/master.m3u8', - type: 'application/vnd.apple.mpegurl' - }); + this.resetNavigatorConnection = (connection = {}) => { + // Need to delete the property before setting since navigator doesn't have a setter + delete window.navigator; + window.navigator = { + connection + }; + }; + }); - this.clock.tick(1); + hooks.afterEach(function() { + this.env.restore(); + window.navigator = this.ogNavigator; + }); - this.player.tech_.vhs.bandwidth = 20e10; - this.player.tech_.vhs.effectiveBandwidthInBits_ = 10e10; - this.player.tech_.vhs.throughput = 20e10; - // 1 / ( 1 / 20e10 + 1 / 20e10) = 10e10 - assert.strictEqual( - this.player.tech_.vhs.systemBandwidth, - 10e10, - 'systemBandwidth is the combination of player bandwidth and throughput' - ); - } -); + QUnit.test( + 'systemBandwidth retrieves bandwidth from networkInformation when option is enabled', + function(assert) { + this.resetNavigatorConnection({ + downlink: 200000 + }); + this.player = createPlayer({ html5: { vhs: { useNetworkInformationApi: true } } }); + this.player.src({ + src: 'manifest/master.m3u8', + type: 'application/vnd.apple.mpegurl' + }); -QUnit.test( - 'effectiveBandwidthInBits_ default', - function(assert) { - this.player.src({ - src: 'manifest/master.m3u8', - type: 'application/vnd.apple.mpegurl' - }); + this.clock.tick(1); - this.clock.tick(1); + this.player.tech_.vhs.throughput = 20e10; + // downlink in bits = 200000 * 1000000 = 20e10 + // 1 / ( 1 / 20e10 + 1 / 20e10) = 10e10 + assert.strictEqual( + this.player.tech_.vhs.systemBandwidth, + 10e10, + 'systemBandwidth is the combination of networkInfo.downlink and throughput' + ); + } + ); - assert.strictEqual( - this.player.tech_.vhs.effectiveBandwidthInBits_, - 0, - 'effectiveBandwidthInBits_ defaults to 0' - ); - } -); + QUnit.test( + 'systemBandwidth uses player-estimated bandwidth when its value is greater than networkInformation.downLink', + function(assert) { + this.resetNavigatorConnection({ + downlink: 100000 + }); + this.player = createPlayer({ html5: { vhs: { useNetworkInformationApi: true } } }); + this.player.src({ + src: 'manifest/master.m3u8', + type: 'application/vnd.apple.mpegurl' + }); -QUnit.test( - 'systemBandwidth uses player-estimated bandwidth when networkInformation is not supported', - function(assert) { - const ogNavigator = window.navigator; + this.clock.tick(1); - // Need to delete the property before setting since navigator doesn't have a setter - delete window.navigator; - window.navigator = {}; - this.player = createPlayer({ html5: { vhs: { useNetworkInformation: true } } }); - this.player.src({ - src: 'manifest/master.m3u8', - type: 'application/vnd.apple.mpegurl' - }); + this.player.tech_.vhs.bandwidth = 20e10; + this.player.tech_.vhs.throughput = 20e10; + // 1 / ( 1 / 20e10 + 1 / 20e10) = 10e10 + assert.strictEqual( + this.player.tech_.vhs.systemBandwidth, + 10e10, + 'systemBandwidth is the combination of player bandwidth and throughput' + ); + } + ); - this.clock.tick(1); + QUnit.test( + 'systemBandwidth uses player-estimated bandwidth when networkInformation is not supported', + function(assert) { + // Nullify the `connection` property on Navigator + this.resetNavigatorConnection(null); + this.player = createPlayer({ html5: { vhs: { useNetworkInformationApi: true } } }); + this.player.src({ + src: 'manifest/master.m3u8', + type: 'application/vnd.apple.mpegurl' + }); - this.player.tech_.vhs.bandwidth = 20e10; - this.player.tech_.vhs.throughput = 20e10; - // 1 / ( 1 / 20e10 + 1 / 20e10) = 10e10 - assert.strictEqual( - this.player.tech_.vhs.systemBandwidth, - 10e10, - 'systemBandwidth is the combination of player bandwidth and throughput since networkInformation is not supported' - ); + this.clock.tick(1); - window.navigator = ogNavigator; - } -); + this.player.tech_.vhs.bandwidth = 20e10; + this.player.tech_.vhs.throughput = 20e10; + // 1 / ( 1 / 20e10 + 1 / 20e10) = 10e10 + assert.strictEqual( + this.player.tech_.vhs.systemBandwidth, + 10e10, + 'systemBandwidth is the combination of player bandwidth and throughput since networkInformation is not supported' + ); + } + ); +}); QUnit.test('requests a reasonable rendition to start', function(assert) { this.player.src({ From 99c34f541c49d1e639d2249f3bdcf76b0f7a0e94 Mon Sep 17 00:00:00 2001 From: Evan farina Date: Tue, 2 Nov 2021 14:05:20 -0400 Subject: [PATCH 4/9] Move use of networkInfo.downlink into the bandwidth getter from the systemBandwidth getter --- src/videojs-http-streaming.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/videojs-http-streaming.js b/src/videojs-http-streaming.js index a817a9599..600a473c4 100644 --- a/src/videojs-http-streaming.js +++ b/src/videojs-http-streaming.js @@ -795,7 +795,19 @@ class VhsHandler extends Component { }, bandwidth: { get() { - return this.masterPlaylistController_.mainSegmentLoader_.bandwidth; + let bandwidthEst = this.masterPlaylistController_.mainSegmentLoader_.bandwidth; + + // NetworkInfo.downlink maxes out at 10 Mbps. In the event that the player estimates a bandwidth + // greater than 10 Mbps, use the larger value to ensure that high quality streams are not + // accidentally filtered out + if (this.options_.useNetworkInformationApi && this.networkInformation) { + // Downlink property returns Mbps https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlink + const effectiveBandwidthBitsPerSec = this.networkInformation.downlink * 1000 * 1000; + + bandwidthEst = Math.max(bandwidthEst, effectiveBandwidthBitsPerSec); + } + + return bandwidthEst; }, set(bandwidth) { this.masterPlaylistController_.mainSegmentLoader_.bandwidth = bandwidth; @@ -819,19 +831,7 @@ class VhsHandler extends Component { */ systemBandwidth: { get() { - let bandwidthEst = this.bandwidth; - - // NetworkInfo.downlink maxes out at 10 Mbps. In the event that the player estimates a bandwidth - // greater than 10 Mbps, use the larger value to ensure that high quality streams are not - // accidentally filtered out - if (this.options_.useNetworkInformationApi && this.networkInformation) { - // Downlink property returns Mbps https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlink - const effectiveBandwidthBitsPerSec = this.networkInformation.downlink * 1000 * 1000; - - bandwidthEst = Math.max(bandwidthEst, effectiveBandwidthBitsPerSec); - } - - const invBandwidth = 1 / (bandwidthEst || 1); + const invBandwidth = 1 / (this.bandwidth || 1); let invThroughput; if (this.throughput > 0) { From c5b2d79dfa54f380afe76bc6eecd9b58999052ae Mon Sep 17 00:00:00 2001 From: Evan farina Date: Tue, 2 Nov 2021 14:10:03 -0400 Subject: [PATCH 5/9] Update tests to assert against vhs.bandwidth as opposed to vhs.systemBandwidth --- test/videojs-http-streaming.test.js | 30 ++++++++++++----------------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/test/videojs-http-streaming.test.js b/test/videojs-http-streaming.test.js index fbb3be6e2..0af8cc033 100644 --- a/test/videojs-http-streaming.test.js +++ b/test/videojs-http-streaming.test.js @@ -1181,7 +1181,7 @@ QUnit.module('NetworkInformationApi', hooks => { }); QUnit.test( - 'systemBandwidth retrieves bandwidth from networkInformation when option is enabled', + 'bandwidth returns networkInformation.downlink when useNetworkInformationApi option is enabled', function(assert) { this.resetNavigatorConnection({ downlink: 200000 @@ -1194,19 +1194,17 @@ QUnit.module('NetworkInformationApi', hooks => { this.clock.tick(1); - this.player.tech_.vhs.throughput = 20e10; // downlink in bits = 200000 * 1000000 = 20e10 - // 1 / ( 1 / 20e10 + 1 / 20e10) = 10e10 assert.strictEqual( - this.player.tech_.vhs.systemBandwidth, - 10e10, - 'systemBandwidth is the combination of networkInfo.downlink and throughput' + this.player.tech_.vhs.bandwidth, + 20e10, + 'bandwidth equals networkInfo.downlink represented as bits per second' ); } ); QUnit.test( - 'systemBandwidth uses player-estimated bandwidth when its value is greater than networkInformation.downLink', + 'bandwidth uses player-estimated bandwidth when its value is greater than networkInformation.downLink', function(assert) { this.resetNavigatorConnection({ downlink: 100000 @@ -1220,18 +1218,16 @@ QUnit.module('NetworkInformationApi', hooks => { this.clock.tick(1); this.player.tech_.vhs.bandwidth = 20e10; - this.player.tech_.vhs.throughput = 20e10; - // 1 / ( 1 / 20e10 + 1 / 20e10) = 10e10 assert.strictEqual( - this.player.tech_.vhs.systemBandwidth, - 10e10, - 'systemBandwidth is the combination of player bandwidth and throughput' + this.player.tech_.vhs.bandwidth, + 20e10, + 'bandwidth getter returned the player-estimated bandwidth value' ); } ); QUnit.test( - 'systemBandwidth uses player-estimated bandwidth when networkInformation is not supported', + 'bandwidth uses player-estimated bandwidth when networkInformation is not supported', function(assert) { // Nullify the `connection` property on Navigator this.resetNavigatorConnection(null); @@ -1244,12 +1240,10 @@ QUnit.module('NetworkInformationApi', hooks => { this.clock.tick(1); this.player.tech_.vhs.bandwidth = 20e10; - this.player.tech_.vhs.throughput = 20e10; - // 1 / ( 1 / 20e10 + 1 / 20e10) = 10e10 assert.strictEqual( - this.player.tech_.vhs.systemBandwidth, - 10e10, - 'systemBandwidth is the combination of player bandwidth and throughput since networkInformation is not supported' + this.player.tech_.vhs.bandwidth, + 20e10, + 'bandwidth getter returned the player-estimated bandwidth value' ); } ); From 74ba0345e6ec575dcb21da060505044ad69d57f9 Mon Sep 17 00:00:00 2001 From: Evan Farina Date: Tue, 2 Nov 2021 16:29:22 -0400 Subject: [PATCH 6/9] Update src/videojs-http-streaming.js Co-authored-by: Garrett Singer --- src/videojs-http-streaming.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/videojs-http-streaming.js b/src/videojs-http-streaming.js index 600a473c4..e3c04dd94 100644 --- a/src/videojs-http-streaming.js +++ b/src/videojs-http-streaming.js @@ -797,13 +797,16 @@ class VhsHandler extends Component { get() { let bandwidthEst = this.masterPlaylistController_.mainSegmentLoader_.bandwidth; - // NetworkInfo.downlink maxes out at 10 Mbps. In the event that the player estimates a bandwidth - // greater than 10 Mbps, use the larger value to ensure that high quality streams are not - // accidentally filtered out - if (this.options_.useNetworkInformationApi && this.networkInformation) { - // Downlink property returns Mbps https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlink + const networkInformation = window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection; + + if (this.options_.useNetworkInformationApi && networkInformation) { + // downlink returns Mbps + // https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlink const effectiveBandwidthBitsPerSec = this.networkInformation.downlink * 1000 * 1000; + // downlink maxes out at 10 Mbps. In the event that the player estimates a bandwidth + // greater than 10 Mbps, use the larger value to ensure that high quality streams are not + // filtered out. bandwidthEst = Math.max(bandwidthEst, effectiveBandwidthBitsPerSec); } From 7cbc014b9aab4c0827cc8285ee933b04615cabb1 Mon Sep 17 00:00:00 2001 From: Evan farina Date: Tue, 2 Nov 2021 16:38:43 -0400 Subject: [PATCH 7/9] Remove private variable for networkInfo --- scripts/index.js | 2 +- src/videojs-http-streaming.js | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/scripts/index.js b/scripts/index.js index 16464165f..4a6d2c35e 100644 --- a/scripts/index.js +++ b/scripts/index.js @@ -568,7 +568,7 @@ experimentalLLHLS: getInputValue(stateEls.llhls), experimentalExactManifestTimings: getInputValue(stateEls['exact-manifest-timings']), experimentalLeastPixelDiffSelector: getInputValue(stateEls['pixel-diff-selector']), - useNetworkInformation: getInputValue(stateEls['network-info']) + useNetworkInformationApi: getInputValue(stateEls['network-info']) } } }); diff --git a/src/videojs-http-streaming.js b/src/videojs-http-streaming.js index e3c04dd94..62b1407aa 100644 --- a/src/videojs-http-streaming.js +++ b/src/videojs-http-streaming.js @@ -617,10 +617,6 @@ class VhsHandler extends Component { }); this.on(this.tech_, 'play', this.play); - - if (this.options_.useNetworkInformationApi) { - this.networkInformation = window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection; - } } setOptions_() { @@ -797,12 +793,12 @@ class VhsHandler extends Component { get() { let bandwidthEst = this.masterPlaylistController_.mainSegmentLoader_.bandwidth; - const networkInformation = window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection; + const networkInformation = window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection; if (this.options_.useNetworkInformationApi && networkInformation) { // downlink returns Mbps // https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlink - const effectiveBandwidthBitsPerSec = this.networkInformation.downlink * 1000 * 1000; + const effectiveBandwidthBitsPerSec = networkInformation.downlink * 1000 * 1000; // downlink maxes out at 10 Mbps. In the event that the player estimates a bandwidth // greater than 10 Mbps, use the larger value to ensure that high quality streams are not From d6d6713303b39eb7664a545fd7c41d578cecf146 Mon Sep 17 00:00:00 2001 From: Evan farina Date: Tue, 2 Nov 2021 17:54:07 -0400 Subject: [PATCH 8/9] Move networkInfo option in demo above experimental options --- index.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/index.html b/index.html index 30fbe10ce..77ccf83fd 100644 --- a/index.html +++ b/index.html @@ -146,6 +146,11 @@
+
+ + +
+
@@ -166,11 +171,6 @@
-
- - -
-
From 833456439c29f4276773d6f9bf178cabac203d91 Mon Sep 17 00:00:00 2001 From: Evan farina Date: Wed, 3 Nov 2021 12:24:42 -0400 Subject: [PATCH 9/9] 1. Expanded networkInfo docs. 2. Only return max of bandwidth estimates if both estimates are >= 10 Mbps --- README.md | 2 +- src/videojs-http-streaming.js | 21 ++++++++++------ test/videojs-http-streaming.test.js | 39 +++++++++++++++++++++++------ 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 95850bf5c..ef4c480eb 100644 --- a/README.md +++ b/README.md @@ -477,7 +477,7 @@ This option defaults to `false`. ##### useNetworkInformationApi * Type: `boolean`, * Default: `false` -* Use [window.networkInformation.downlink](https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlink) to estimate the network's bandwidth +* 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. ##### captionServices * Type: `object` diff --git a/src/videojs-http-streaming.js b/src/videojs-http-streaming.js index 62b1407aa..813ed4230 100644 --- a/src/videojs-http-streaming.js +++ b/src/videojs-http-streaming.js @@ -791,22 +791,27 @@ class VhsHandler extends Component { }, bandwidth: { get() { - let bandwidthEst = this.masterPlaylistController_.mainSegmentLoader_.bandwidth; + let playerBandwidthEst = this.masterPlaylistController_.mainSegmentLoader_.bandwidth; const networkInformation = window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection; + const tenMbpsAsBitsPerSecond = 10e6; if (this.options_.useNetworkInformationApi && networkInformation) { // downlink returns Mbps // https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlink - const effectiveBandwidthBitsPerSec = networkInformation.downlink * 1000 * 1000; - - // downlink maxes out at 10 Mbps. In the event that the player estimates a bandwidth - // greater than 10 Mbps, use the larger value to ensure that high quality streams are not - // filtered out. - bandwidthEst = Math.max(bandwidthEst, effectiveBandwidthBitsPerSec); + const networkInfoBandwidthEstBitsPerSec = networkInformation.downlink * 1000 * 1000; + + // 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. + if (networkInfoBandwidthEstBitsPerSec >= tenMbpsAsBitsPerSecond && playerBandwidthEst >= tenMbpsAsBitsPerSecond) { + playerBandwidthEst = Math.max(playerBandwidthEst, networkInfoBandwidthEstBitsPerSec); + } else { + playerBandwidthEst = networkInfoBandwidthEstBitsPerSec; + } } - return bandwidthEst; + return playerBandwidthEst; }, set(bandwidth) { this.masterPlaylistController_.mainSegmentLoader_.bandwidth = bandwidth; diff --git a/test/videojs-http-streaming.test.js b/test/videojs-http-streaming.test.js index 0af8cc033..2825d6c95 100644 --- a/test/videojs-http-streaming.test.js +++ b/test/videojs-http-streaming.test.js @@ -1184,7 +1184,7 @@ QUnit.module('NetworkInformationApi', hooks => { 'bandwidth returns networkInformation.downlink when useNetworkInformationApi option is enabled', function(assert) { this.resetNavigatorConnection({ - downlink: 200000 + downlink: 10 }); this.player = createPlayer({ html5: { vhs: { useNetworkInformationApi: true } } }); this.player.src({ @@ -1194,20 +1194,21 @@ QUnit.module('NetworkInformationApi', hooks => { this.clock.tick(1); - // downlink in bits = 200000 * 1000000 = 20e10 + // downlink in bits = 10 * 1000000 = 10e6 assert.strictEqual( this.player.tech_.vhs.bandwidth, - 20e10, + 10e6, 'bandwidth equals networkInfo.downlink represented as bits per second' ); } ); QUnit.test( - 'bandwidth uses player-estimated bandwidth when its value is greater than networkInformation.downLink', + 'bandwidth uses player-estimated bandwidth when its value is greater than networkInformation.downLink and both values are >= 10 Mbps', function(assert) { this.resetNavigatorConnection({ - downlink: 100000 + // 10 Mbps or 10e6 + downlink: 10 }); this.player = createPlayer({ html5: { vhs: { useNetworkInformationApi: true } } }); this.player.src({ @@ -1217,15 +1218,39 @@ QUnit.module('NetworkInformationApi', hooks => { this.clock.tick(1); - this.player.tech_.vhs.bandwidth = 20e10; + this.player.tech_.vhs.bandwidth = 20e6; assert.strictEqual( this.player.tech_.vhs.bandwidth, - 20e10, + 20e6, 'bandwidth getter returned the player-estimated bandwidth value' ); } ); + QUnit.test( + 'bandwidth uses network-information-api bandwidth when its value is less than the player bandwidth and 10 Mbps', + function(assert) { + this.resetNavigatorConnection({ + // 9 Mbps or 9e6 + downlink: 9 + }); + this.player = createPlayer({ html5: { vhs: { useNetworkInformationApi: true } } }); + this.player.src({ + src: 'manifest/master.m3u8', + type: 'application/vnd.apple.mpegurl' + }); + + this.clock.tick(1); + + this.player.tech_.vhs.bandwidth = 20e10; + assert.strictEqual( + this.player.tech_.vhs.bandwidth, + 9e6, + 'bandwidth getter returned the network-information-api bandwidth value since it was less than 10 Mbps' + ); + } + ); + QUnit.test( 'bandwidth uses player-estimated bandwidth when networkInformation is not supported', function(assert) {