From 8a98460fd6fb58856846d791b2180fade78e0122 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Tue, 25 Oct 2022 00:59:38 +0300 Subject: [PATCH 1/3] Detect bitrate in LAN --- src/apiClient.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/apiClient.js b/src/apiClient.js index 9257139..8ad31ac 100644 --- a/src/apiClient.js +++ b/src/apiClient.js @@ -9,6 +9,8 @@ const reportRateLimits = { /** Maximum bitrate (Int32) */ const MAX_BITRATE = 2147483647; +/** Approximate LAN bitrate */ +const LAN_BITRATE = 140000000; function redetectBitrate(instance) { stopBitrateDetection(instance); @@ -4092,13 +4094,6 @@ function detectBitrateInternal(instance, tests, index, currentBitrate) { } function detectBitrateWithEndpointInfo(instance, endpointInfo) { - if (endpointInfo.IsInNetwork) { - const result = 140000000; - instance.lastDetectedBitrate = result; - instance.lastDetectedBitrateTime = new Date().getTime(); - return result; - } - return detectBitrateInternal( instance, [ @@ -4116,7 +4111,15 @@ function detectBitrateWithEndpointInfo(instance, endpointInfo) { } ], 0 - ); + ).then((result) => { + if (endpointInfo.IsInNetwork) { + result = Math.max(result || 0, LAN_BITRATE); + + instance.lastDetectedBitrate = result; + instance.lastDetectedBitrateTime = new Date().getTime(); + } + return result; + }); } function getRemoteImagePrefix(instance, options) { From 1d4bb283922282fb8be09dd2802e2f20d11bd6dc Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Tue, 25 Oct 2022 18:03:06 +0300 Subject: [PATCH 2/3] Rewrite bitrate test Use XMLHttpRequest to measure the actual loading stage and get the actual number of bytes loaded. --- src/apiClient.js | 72 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/src/apiClient.js b/src/apiClient.js index 8ad31ac..4b0e1f3 100644 --- a/src/apiClient.js +++ b/src/apiClient.js @@ -11,6 +11,8 @@ const reportRateLimits = { const MAX_BITRATE = 2147483647; /** Approximate LAN bitrate */ const LAN_BITRATE = 140000000; +/** Bitrate test timeout in milliseconds */ +const BITRATETEST_TIMEOUT = 5000; function redetectBitrate(instance) { stopBitrateDetection(instance); @@ -748,22 +750,66 @@ class ApiClient { } getDownloadSpeed(byteSize) { - const url = this.getUrl('Playback/BitrateTest', { - Size: byteSize - }); + return new Promise((resolve, reject) => { + const url = this.getUrl('Playback/BitrateTest', { + Size: byteSize + }); - const now = new Date().getTime(); + console.log(`Requesting ${url}`); - return this.ajax({ - type: 'GET', - url, - timeout: 5000 - }).then(() => { - const responseTimeSeconds = (new Date().getTime() - now) / 1000; - const bytesPerSecond = byteSize / responseTimeSeconds; - const bitrate = Math.round(bytesPerSecond * 8); + const xhr = new XMLHttpRequest; + + xhr.open('GET', url, true); + + xhr.responseType = 'blob'; + xhr.timeout = BITRATETEST_TIMEOUT; + + const headers = { + 'Cache-Control': 'no-cache, no-store' + }; + + this.setRequestHeaders(headers); + + for (const key in headers) { + xhr.setRequestHeader(key, headers[key]); + } + + let startTime; + + xhr.onreadystatechange = () => { + if (xhr.readyState == XMLHttpRequest.HEADERS_RECEIVED) { + startTime = performance.now(); + } + }; + + xhr.onload = () => { + if (xhr.status < 400) { + const responseTimeSeconds = (performance.now() - startTime) * 1e-3; + const bytesLoaded = xhr.response.size; + const bytesPerSecond = bytesLoaded / responseTimeSeconds; + const bitrate = Math.round(bytesPerSecond * 8); + + console.debug(`BitrateTest ${bytesLoaded} bytes loaded (${byteSize} requested) in ${responseTimeSeconds} seconds -> ${bitrate} bps`); + + resolve(bitrate); + } else { + reject(`BitrateTest failed with ${xhr.status} status`); + } + }; + + xhr.onabort = () => { + reject('BitrateTest abort'); + }; + + xhr.onerror = () => { + reject('BitrateTest error'); + }; + + xhr.ontimeout = () => { + reject('BitrateTest timeout'); + }; - return bitrate; + xhr.send(null); }); } From eccf6561e8cd1e9e6a609fe0b2f8fb2be08fd7fe Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Wed, 26 Oct 2022 19:13:10 +0300 Subject: [PATCH 3/3] fix cleanup of detection timeout --- src/apiClient.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/apiClient.js b/src/apiClient.js index 4b0e1f3..3d32349 100644 --- a/src/apiClient.js +++ b/src/apiClient.js @@ -18,11 +18,13 @@ function redetectBitrate(instance) { stopBitrateDetection(instance); if (instance.accessToken() && instance.enableAutomaticBitrateDetection !== false) { - setTimeout(redetectBitrateInternal.bind(instance), 6000); + instance.detectTimeout = setTimeout(redetectBitrateInternal.bind(instance), 6000); } } function redetectBitrateInternal() { + this.detectTimeout = null; + if (this.accessToken()) { this.detectBitrate(); } @@ -31,6 +33,7 @@ function redetectBitrateInternal() { function stopBitrateDetection(instance) { if (instance.detectTimeout) { clearTimeout(instance.detectTimeout); + instance.detectTimeout = null; } }