Browse Source

Continued tweaking of latency compensation

pull/1799/head
Gabe Kangas 3 years ago
parent
commit
d96ddcc6c6
No known key found for this signature in database
GPG Key ID: 9A56337728BC81EA
  1. 50
      webroot/js/components/latencyCompensator.js
  2. 9
      webroot/js/components/player.js

50
webroot/js/components/latencyCompensator.js

@ -11,7 +11,7 @@ It will:
- Completely give up on all compensation if too many buffering events occur. - Completely give up on all compensation if too many buffering events occur.
*/ */
const REBUFFER_EVENT_LIMIT = 8; // Max number of buffering events before we stop compensating for latency. const REBUFFER_EVENT_LIMIT = 5; // Max number of buffering events before we stop compensating for latency.
const MIN_BUFFER_DURATION = 300; // Min duration a buffer event must last to be counted. const MIN_BUFFER_DURATION = 300; // Min duration a buffer event must last to be counted.
const MAX_SPEEDUP_RATE = 1.07; // The playback rate when compensating for latency. const MAX_SPEEDUP_RATE = 1.07; // The playback rate when compensating for latency.
const TIMEOUT_DURATION = 20_000; // The amount of time we stop handling latency after certain events. const TIMEOUT_DURATION = 20_000; // The amount of time we stop handling latency after certain events.
@ -24,7 +24,7 @@ const REQUIRED_BANDWIDTH_RATIO = 2.0; // The player:bitrate ratio required to en
class LatencyCompensator { class LatencyCompensator {
constructor(player) { constructor(player) {
this.player = player; this.player = player;
this.enabled = true; this.enabled = false;
this.running = false; this.running = false;
this.inTimeout = false; this.inTimeout = false;
this.timeoutTimer = 0; this.timeoutTimer = 0;
@ -64,13 +64,24 @@ class LatencyCompensator {
} }
let proposedPlaybackRate = bandwidthRatio * 0.34; let proposedPlaybackRate = bandwidthRatio * 0.34;
console.log('proposed rate', proposedPlaybackRate, this.running); console.log('proposed rate', proposedPlaybackRate);
proposedPlaybackRate = Math.max( proposedPlaybackRate = Math.max(
Math.min(proposedPlaybackRate, MAX_SPEEDUP_RATE), Math.min(proposedPlaybackRate, MAX_SPEEDUP_RATE),
1.0 1.0
); );
console.log('playback rate', proposedPlaybackRate, this.running); console.log(
'playback rate',
proposedPlaybackRate,
'enabled:',
this.enabled,
'running: ',
this.running,
'timedout: ',
this.inTimeout,
'buffer count:',
this.bufferingCounter
);
try { try {
const segment = getCurrentlyPlayingSegment(tech); const segment = getCurrentlyPlayingSegment(tech);
if (!segment) { if (!segment) {
@ -103,7 +114,7 @@ class LatencyCompensator {
} }
start(rate = 1.0) { start(rate = 1.0) {
if (this.inTimeout || this.disabled) { if (this.inTimeout || !this.enabled) {
return; return;
} }
@ -116,6 +127,16 @@ class LatencyCompensator {
this.player.playbackRate(1); this.player.playbackRate(1);
} }
enable() {
this.enabled = true;
clearInterval(this.checkTimer);
clearTimeout(this.bufferingTimer);
this.checkTimer = setInterval(() => {
this.check();
}, CHECK_TIMER_INTERVAL);
}
// Disable means we're done for good and should no longer compensate for latency. // Disable means we're done for good and should no longer compensate for latency.
disable() { disable() {
clearInterval(this.checkTimer); clearInterval(this.checkTimer);
@ -158,25 +179,28 @@ class LatencyCompensator {
this.endTimeout(); this.endTimeout();
} }
} }
clearInterval(this.checkTimer);
clearTimeout(this.bufferingTimer);
this.checkTimer = setInterval(() => {
this.check();
}, CHECK_TIMER_INTERVAL);
} }
handleEnded() { handleEnded() {
if (!this.enabled) {
return;
}
this.disable(); this.disable();
} }
handleError() { handleError() {
if (!this.enabled) {
return;
}
this.timeout(); this.timeout();
} }
countBufferingEvent() { countBufferingEvent() {
this.bufferingCounter++; this.bufferingCounter++;
if (this.bufferingCounter > REBUFFER_EVENT_LIMIT) { if (this.bufferingCounter > REBUFFER_EVENT_LIMIT) {
console.log('disabling latency compensation');
this.disable(); this.disable();
return; return;
} }
@ -192,6 +216,10 @@ class LatencyCompensator {
} }
handleBuffering() { handleBuffering() {
if (!this.enabled) {
return;
}
this.bufferStartedTimestamp = new Date().getTime(); this.bufferStartedTimestamp = new Date().getTime();
this.timeout(); this.timeout();
} }

9
webroot/js/components/player.js

@ -236,7 +236,14 @@ class OwncastPlayer {
this.appPlayerPlayingCallback(); this.appPlayerPlayingCallback();
} }
this.latencyCompensator.enable();
setInterval(() => { setInterval(() => {
this.collectPlaybackMetrics();
}, 5000);
}
collectPlaybackMetrics() {
const tech = this.vjsPlayer.tech({ IWillNotUseThisInPlugins: true }); const tech = this.vjsPlayer.tech({ IWillNotUseThisInPlugins: true });
const bandwidth = tech.vhs.systemBandwidth; const bandwidth = tech.vhs.systemBandwidth;
this.playbackMetrics.trackBandwidth(bandwidth); this.playbackMetrics.trackBandwidth(bandwidth);
@ -250,7 +257,6 @@ class OwncastPlayer {
} catch (err) { } catch (err) {
console.warn(err); console.warn(err);
} }
}, 5000);
} }
handleEnded() { handleEnded() {
@ -258,6 +264,7 @@ class OwncastPlayer {
if (this.appPlayerEndedCallback) { if (this.appPlayerEndedCallback) {
this.appPlayerEndedCallback(); this.appPlayerEndedCallback();
} }
this.latencyCompensator.disable();
} }
handleError(e) { handleError(e) {

Loading…
Cancel
Save