Skip to content

Commit

Permalink
feat: Stop setting playbackRate to 0 to control buffering state when …
Browse files Browse the repository at this point in the history
…streaming.rebufferingGoal = 0 (#7617)

Close #7602
  • Loading branch information
avelad authored Nov 20, 2024
1 parent bc0b9f2 commit 84b64af
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 25 deletions.
3 changes: 2 additions & 1 deletion demo/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,8 @@ shakaDemo.Config = class {
.addNumberInput_('Duration Backoff', 'streaming.durationBackoff',
/* canBeDecimal= */ true)
.addNumberInput_('Rebuffering Goal', 'streaming.rebufferingGoal',
/* canBeDecimal= */ true)
/* canBeDecimal= */ true,
/* canBeZero= */ true)
.addNumberInput_('Buffer Behind', 'streaming.bufferBehind',
/* canBeDecimal= */ true)
.addNumberInput_('Eviction Goal', 'streaming.evictionGoal',
Expand Down
6 changes: 2 additions & 4 deletions docs/tutorials/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ player.getConfiguration();
failureCallback: Function
ignoreTextStreamFailures: false
alwaysStreamText: false
rebufferingGoal: 2
rebufferingGoal: 0
retryParameters: Object
startAtSegmentBoundary: false
safeSeekOffset: 5
Expand Down Expand Up @@ -103,7 +103,7 @@ player.getConfiguration().preferredAudioLanguage
// check buffering goal, which is 2 minutes:
player.getConfiguration().streaming.bufferingGoal

// check rebuffering goal, which is still the default of 2 seconds:
// check rebuffering goal, which is still the default of 0 seconds:
player.getConfiguration().streaming.rebufferingGoal

// set the rebuffering goal to 15 seconds and revert buffering goal to default:
Expand All @@ -124,7 +124,6 @@ buffering settings) while some will not have any effect until the next call to

With `.streaming.lowLatencyMode` set to true,
`.streaming.inaccurateManifestTolerance` is set to 0 by default,
`.streaming.rebufferingGoal` is set to 0.01 by default,
`.streaming.segmentPrefetchLimit` is set to 2 by default,
`.streaming.updateIntervalSeconds` is set to 0.1 by default,
`.streaming.maxDisabledTime` is set to 1 by default,
Expand All @@ -141,7 +140,6 @@ player.configure({
streaming: {
lowLatencyMode: true,
inaccurateManifestTolerance: 0,
rebufferingGoal: 0.01,
segmentPrefetchLimit: 2,
updateIntervalSeconds: 0.1,
maxDisabledTime: 1,
Expand Down
3 changes: 2 additions & 1 deletion externs/shaka/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -1590,8 +1590,9 @@ shaka.extern.LiveSyncConfiguration;
* buffer before it can begin playback or can continue playback after it has
* entered into a buffering state (i.e., after it has depleted one more
* more of its buffers).
* When the value is 0, the playback rate is not used to control the buffer.
* <br>
* Defaults to <code>2</code>.
* Defaults to <code>0</code>.
* @property {number} bufferingGoal
* The number of seconds of content that the StreamingEngine will attempt to
* buffer ahead of the playhead. This value must be greater than or equal to
Expand Down
7 changes: 4 additions & 3 deletions lib/media/buffering_observer.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ shaka.media.BufferingObserver = class {
const threshold = this.thresholds_.get(this.previousState_);

const oldState = this.previousState_;
const newState = (bufferedToEnd || bufferLead >= threshold) ?
(State.SATISFIED) :
(State.STARVING);
const newState =
(bufferedToEnd || (bufferLead >= threshold && bufferLead > 0)) ?
(State.SATISFIED) :
(State.STARVING);

// Save the new state now so that calls to |getState| from any callbacks
// will be accurate.
Expand Down
28 changes: 21 additions & 7 deletions lib/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -3634,7 +3634,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {

this.bufferPoller_ = new shaka.util.Timer(() => {
this.pollBufferState_();
}).tickEvery(/* seconds= */ 0.25);
});
if (this.config_.streaming.rebufferingGoal) {
this.bufferPoller_.tickEvery(/* seconds= */ 0.25);
}
this.loadEventManager_.listen(mediaElement, 'waiting',
(e) => this.pollBufferState_());
this.loadEventManager_.listen(mediaElement, 'stalled',
Expand All @@ -3643,6 +3646,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
(e) => this.pollBufferState_());
this.loadEventManager_.listen(mediaElement, 'progress',
(e) => this.pollBufferState_());
this.loadEventManager_.listen(mediaElement, 'seeked',
(e) => this.pollBufferState_());
}

/**
Expand Down Expand Up @@ -4030,19 +4035,16 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
}

// If lowLatencyMode is enabled, and inaccurateManifestTolerance and
// rebufferingGoal and segmentPrefetchLimit and baseDelay and
// segmentPrefetchLimit and baseDelay and
// autoCorrectDrift and maxDisabledTime are not specified, set
// inaccurateManifestTolerance to 0 and rebufferingGoal to 0.01 and
// inaccurateManifestTolerance to 0 and and
// segmentPrefetchLimit to 2 and updateIntervalSeconds to 0.1 and and
// baseDelay to 100 and autoCorrectDrift to false and maxDisabledTime
// to 1 by default for low latency streaming.
if (config['streaming'] && config['streaming']['lowLatencyMode']) {
if (config['streaming']['inaccurateManifestTolerance'] == undefined) {
config['streaming']['inaccurateManifestTolerance'] = 0;
}
if (config['streaming']['rebufferingGoal'] == undefined) {
config['streaming']['rebufferingGoal'] = 0.01;
}
if (config['streaming']['segmentPrefetchLimit'] == undefined) {
config['streaming']['segmentPrefetchLimit'] = 2;
}
Expand Down Expand Up @@ -4204,6 +4206,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
if (this.bufferObserver_) {
this.updateBufferingSettings_(this.config_.streaming.rebufferingGoal);
}
if (this.bufferPoller_) {
if (!this.config_.streaming.rebufferingGoal) {
this.bufferPoller_.stop();
} else {
this.bufferPoller_.tickEvery(/* seconds= */ 0.25);
}
}

if (this.manifest_) {
shaka.Player.applyPlayRange_(this.manifest_.presentationTimeline,
Expand Down Expand Up @@ -6721,7 +6730,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
const loaded = this.stats_ && this.bufferObserver_ && this.playhead_;

if (loaded) {
this.playRateController_.setBuffering(isBuffering);
if (this.config_.streaming.rebufferingGoal == 0) {
// Disable buffer control with playback rate
this.playRateController_.setBuffering(/* isBuffering= */ false);
} else {
this.playRateController_.setBuffering(isBuffering);
}
if (this.cmcdManager_) {
this.cmcdManager_.setBuffering(isBuffering);
}
Expand Down
4 changes: 1 addition & 3 deletions lib/util/player_configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,7 @@ shaka.util.PlayerConfiguration = class {
[error],
undefined);
},
// When low latency streaming is enabled, rebufferingGoal will default to
// 0.01 if not specified.
rebufferingGoal: 2,
rebufferingGoal: 0,
bufferingGoal: 10,
bufferBehind: 30,
evictionGoal: 1,
Expand Down
8 changes: 2 additions & 6 deletions test/player_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -1291,7 +1291,6 @@ describe('Player', () => {
player.configure({
streaming: {
lowLatencyMode: true,
rebufferingGoal: 1,
inaccurateManifestTolerance: 1,
segmentPrefetchLimit: 1,
updateIntervalSeconds: 10,
Expand All @@ -1314,7 +1313,6 @@ describe('Player', () => {
},
},
});
expect(player.getConfiguration().streaming.rebufferingGoal).toBe(1);
expect(player.getConfiguration().streaming.inaccurateManifestTolerance)
.toBe(1);
expect(player.getConfiguration().streaming.segmentPrefetchLimit).toBe(1);
Expand All @@ -1330,12 +1328,10 @@ describe('Player', () => {
expect(player.getConfiguration().drm.retryParameters.baseDelay)
.toBe(2000);

// When low latency streaming gets enabled, rebufferingGoal will default
// to 0.01 if unless specified, inaccurateManifestTolerance will
// default to 0 unless specified, and segmentPrefetchLimit will
// When low latency streaming gets enabled, inaccurateManifestTolerance
// will default to 0 unless specified, and segmentPrefetchLimit will
// default to 2 unless specified.
player.configure('streaming.lowLatencyMode', true);
expect(player.getConfiguration().streaming.rebufferingGoal).toBe(0.01);
expect(player.getConfiguration().streaming.inaccurateManifestTolerance)
.toBe(0);
expect(player.getConfiguration().streaming.segmentPrefetchLimit).toBe(2);
Expand Down

0 comments on commit 84b64af

Please sign in to comment.