Add targetLiveOffsetUs parameter to LoadControl.shouldStartPlayback
This allows a LoadControl to start playback earlier if the target live offset is very low. Issue: #4904 PiperOrigin-RevId: 336863824
This commit is contained in:
parent
76b7f76437
commit
8fdadade7b
@ -3,6 +3,8 @@
|
|||||||
### dev-v2 (not yet released)
|
### dev-v2 (not yet released)
|
||||||
|
|
||||||
* Core library:
|
* Core library:
|
||||||
|
* `LoadControl`:
|
||||||
|
* Add a `targetLiveOffsetUs` parameter to `shouldStartPlayback`.
|
||||||
* Fix bug where streams with highly uneven durations may get stuck in a
|
* Fix bug where streams with highly uneven durations may get stuck in a
|
||||||
buffering state
|
buffering state
|
||||||
([#7943](https://github.com/google/ExoPlayer/issues/7943)).
|
([#7943](https://github.com/google/ExoPlayer/issues/7943)).
|
||||||
@ -12,8 +14,8 @@
|
|||||||
([#4463](https://github.com/google/ExoPlayer/issues/4463)).
|
([#4463](https://github.com/google/ExoPlayer/issues/4463)).
|
||||||
* Add a getter and callback for static metadata to the player
|
* Add a getter and callback for static metadata to the player
|
||||||
([#7266](https://github.com/google/ExoPlayer/issues/7266)).
|
([#7266](https://github.com/google/ExoPlayer/issues/7266)).
|
||||||
* Time out on release to prevent ANRs if the underlying platform call
|
* Time out on release to prevent ANRs if the underlying platform call is
|
||||||
is stuck ([#4352](https://github.com/google/ExoPlayer/issues/4352)).
|
stuck ([#4352](https://github.com/google/ExoPlayer/issues/4352)).
|
||||||
* Time out when detaching a surface to prevent ANRs if the underlying
|
* Time out when detaching a surface to prevent ANRs if the underlying
|
||||||
platform call is stuck
|
platform call is stuck
|
||||||
([#5887](https://github.com/google/ExoPlayer/issues/5887)).
|
([#5887](https://github.com/google/ExoPlayer/issues/5887)).
|
||||||
@ -48,8 +50,8 @@
|
|||||||
([#7949](https://github.com/google/ExoPlayer/issues/7949)).
|
([#7949](https://github.com/google/ExoPlayer/issues/7949)).
|
||||||
* Fix regression for Ogg files with packets that span multiple pages
|
* Fix regression for Ogg files with packets that span multiple pages
|
||||||
([#7992](https://github.com/google/ExoPlayer/issues/7992)).
|
([#7992](https://github.com/google/ExoPlayer/issues/7992)).
|
||||||
* Add TS extractor parameter to configure the number of bytes in which
|
* Add TS extractor parameter to configure the number of bytes in which to
|
||||||
to search for a timestamp to determine the duration and to seek.
|
search for a timestamp to determine the duration and to seek.
|
||||||
([#7988](https://github.com/google/ExoPlayer/issues/7988)).
|
([#7988](https://github.com/google/ExoPlayer/issues/7988)).
|
||||||
* Ignore negative payload size in PES packets
|
* Ignore negative payload size in PES packets
|
||||||
([#8005](https://github.com/google/ExoPlayer/issues/8005)).
|
([#8005](https://github.com/google/ExoPlayer/issues/8005)).
|
||||||
@ -64,9 +66,9 @@
|
|||||||
* Allow apps to specify a `VideoAdPlayerCallback`
|
* Allow apps to specify a `VideoAdPlayerCallback`
|
||||||
([#7944](https://github.com/google/ExoPlayer/issues/7944)).
|
([#7944](https://github.com/google/ExoPlayer/issues/7944)).
|
||||||
* Accept ad tags via the `AdsMediaSource` constructor and deprecate
|
* Accept ad tags via the `AdsMediaSource` constructor and deprecate
|
||||||
passing them via the `ImaAdsLoader` constructor/builders. Passing the
|
passing them via the `ImaAdsLoader` constructor/builders. Passing the ad
|
||||||
ad tag via media item playback properties continues to be supported.
|
tag via media item playback properties continues to be supported. This
|
||||||
This is in preparation for supporting ads in playlists
|
is in preparation for supporting ads in playlists
|
||||||
([#3750](https://github.com/google/ExoPlayer/issues/3750)).
|
([#3750](https://github.com/google/ExoPlayer/issues/3750)).
|
||||||
|
|
||||||
* UI:
|
* UI:
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2;
|
package com.google.android.exoplayer2;
|
||||||
|
|
||||||
|
import static com.google.android.exoplayer2.util.Assertions.checkState;
|
||||||
import static java.lang.Math.max;
|
import static java.lang.Math.max;
|
||||||
import static java.lang.Math.min;
|
import static java.lang.Math.min;
|
||||||
|
|
||||||
@ -129,7 +130,7 @@ public class DefaultLoadControl implements LoadControl {
|
|||||||
* @throws IllegalStateException If {@link #build()} has already been called.
|
* @throws IllegalStateException If {@link #build()} has already been called.
|
||||||
*/
|
*/
|
||||||
public Builder setAllocator(DefaultAllocator allocator) {
|
public Builder setAllocator(DefaultAllocator allocator) {
|
||||||
Assertions.checkState(!buildCalled);
|
checkState(!buildCalled);
|
||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -154,7 +155,7 @@ public class DefaultLoadControl implements LoadControl {
|
|||||||
int maxBufferMs,
|
int maxBufferMs,
|
||||||
int bufferForPlaybackMs,
|
int bufferForPlaybackMs,
|
||||||
int bufferForPlaybackAfterRebufferMs) {
|
int bufferForPlaybackAfterRebufferMs) {
|
||||||
Assertions.checkState(!buildCalled);
|
checkState(!buildCalled);
|
||||||
assertGreaterOrEqual(bufferForPlaybackMs, 0, "bufferForPlaybackMs", "0");
|
assertGreaterOrEqual(bufferForPlaybackMs, 0, "bufferForPlaybackMs", "0");
|
||||||
assertGreaterOrEqual(
|
assertGreaterOrEqual(
|
||||||
bufferForPlaybackAfterRebufferMs, 0, "bufferForPlaybackAfterRebufferMs", "0");
|
bufferForPlaybackAfterRebufferMs, 0, "bufferForPlaybackAfterRebufferMs", "0");
|
||||||
@ -181,7 +182,7 @@ public class DefaultLoadControl implements LoadControl {
|
|||||||
* @throws IllegalStateException If {@link #build()} has already been called.
|
* @throws IllegalStateException If {@link #build()} has already been called.
|
||||||
*/
|
*/
|
||||||
public Builder setTargetBufferBytes(int targetBufferBytes) {
|
public Builder setTargetBufferBytes(int targetBufferBytes) {
|
||||||
Assertions.checkState(!buildCalled);
|
checkState(!buildCalled);
|
||||||
this.targetBufferBytes = targetBufferBytes;
|
this.targetBufferBytes = targetBufferBytes;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -196,7 +197,7 @@ public class DefaultLoadControl implements LoadControl {
|
|||||||
* @throws IllegalStateException If {@link #build()} has already been called.
|
* @throws IllegalStateException If {@link #build()} has already been called.
|
||||||
*/
|
*/
|
||||||
public Builder setPrioritizeTimeOverSizeThresholds(boolean prioritizeTimeOverSizeThresholds) {
|
public Builder setPrioritizeTimeOverSizeThresholds(boolean prioritizeTimeOverSizeThresholds) {
|
||||||
Assertions.checkState(!buildCalled);
|
checkState(!buildCalled);
|
||||||
this.prioritizeTimeOverSizeThresholds = prioritizeTimeOverSizeThresholds;
|
this.prioritizeTimeOverSizeThresholds = prioritizeTimeOverSizeThresholds;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -212,7 +213,7 @@ public class DefaultLoadControl implements LoadControl {
|
|||||||
* @throws IllegalStateException If {@link #build()} has already been called.
|
* @throws IllegalStateException If {@link #build()} has already been called.
|
||||||
*/
|
*/
|
||||||
public Builder setBackBuffer(int backBufferDurationMs, boolean retainBackBufferFromKeyframe) {
|
public Builder setBackBuffer(int backBufferDurationMs, boolean retainBackBufferFromKeyframe) {
|
||||||
Assertions.checkState(!buildCalled);
|
checkState(!buildCalled);
|
||||||
assertGreaterOrEqual(backBufferDurationMs, 0, "backBufferDurationMs", "0");
|
assertGreaterOrEqual(backBufferDurationMs, 0, "backBufferDurationMs", "0");
|
||||||
this.backBufferDurationMs = backBufferDurationMs;
|
this.backBufferDurationMs = backBufferDurationMs;
|
||||||
this.retainBackBufferFromKeyframe = retainBackBufferFromKeyframe;
|
this.retainBackBufferFromKeyframe = retainBackBufferFromKeyframe;
|
||||||
@ -227,7 +228,7 @@ public class DefaultLoadControl implements LoadControl {
|
|||||||
|
|
||||||
/** Creates a {@link DefaultLoadControl}. */
|
/** Creates a {@link DefaultLoadControl}. */
|
||||||
public DefaultLoadControl build() {
|
public DefaultLoadControl build() {
|
||||||
Assertions.checkState(!buildCalled);
|
checkState(!buildCalled);
|
||||||
buildCalled = true;
|
buildCalled = true;
|
||||||
if (allocator == null) {
|
if (allocator == null) {
|
||||||
allocator = new DefaultAllocator(/* trimOnReset= */ true, C.DEFAULT_BUFFER_SEGMENT_SIZE);
|
allocator = new DefaultAllocator(/* trimOnReset= */ true, C.DEFAULT_BUFFER_SEGMENT_SIZE);
|
||||||
@ -257,7 +258,7 @@ public class DefaultLoadControl implements LoadControl {
|
|||||||
private final boolean retainBackBufferFromKeyframe;
|
private final boolean retainBackBufferFromKeyframe;
|
||||||
|
|
||||||
private int targetBufferBytes;
|
private int targetBufferBytes;
|
||||||
private boolean isBuffering;
|
private boolean isLoading;
|
||||||
|
|
||||||
/** Constructs a new instance, using the {@code DEFAULT_*} constants defined in this class. */
|
/** Constructs a new instance, using the {@code DEFAULT_*} constants defined in this class. */
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@ -394,23 +395,26 @@ public class DefaultLoadControl implements LoadControl {
|
|||||||
// Prevent playback from getting stuck if minBufferUs is too small.
|
// Prevent playback from getting stuck if minBufferUs is too small.
|
||||||
minBufferUs = max(minBufferUs, 500_000);
|
minBufferUs = max(minBufferUs, 500_000);
|
||||||
if (bufferedDurationUs < minBufferUs) {
|
if (bufferedDurationUs < minBufferUs) {
|
||||||
isBuffering = prioritizeTimeOverSizeThresholds || !targetBufferSizeReached;
|
isLoading = prioritizeTimeOverSizeThresholds || !targetBufferSizeReached;
|
||||||
if (!isBuffering && bufferedDurationUs < 500_000) {
|
if (!isLoading && bufferedDurationUs < 500_000) {
|
||||||
Log.w(
|
Log.w(
|
||||||
"DefaultLoadControl",
|
"DefaultLoadControl",
|
||||||
"Target buffer size reached with less than 500ms of buffered media data.");
|
"Target buffer size reached with less than 500ms of buffered media data.");
|
||||||
}
|
}
|
||||||
} else if (bufferedDurationUs >= maxBufferUs || targetBufferSizeReached) {
|
} else if (bufferedDurationUs >= maxBufferUs || targetBufferSizeReached) {
|
||||||
isBuffering = false;
|
isLoading = false;
|
||||||
} // Else don't change the buffering state
|
} // Else don't change the loading state.
|
||||||
return isBuffering;
|
return isLoading;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldStartPlayback(
|
public boolean shouldStartPlayback(
|
||||||
long bufferedDurationUs, float playbackSpeed, boolean rebuffering) {
|
long bufferedDurationUs, float playbackSpeed, boolean rebuffering, long targetLiveOffsetUs) {
|
||||||
bufferedDurationUs = Util.getPlayoutDurationForMediaDuration(bufferedDurationUs, playbackSpeed);
|
bufferedDurationUs = Util.getPlayoutDurationForMediaDuration(bufferedDurationUs, playbackSpeed);
|
||||||
long minBufferDurationUs = rebuffering ? bufferForPlaybackAfterRebufferUs : bufferForPlaybackUs;
|
long minBufferDurationUs = rebuffering ? bufferForPlaybackAfterRebufferUs : bufferForPlaybackUs;
|
||||||
|
if (targetLiveOffsetUs != C.TIME_UNSET) {
|
||||||
|
minBufferDurationUs = min(targetLiveOffsetUs / 2, minBufferDurationUs);
|
||||||
|
}
|
||||||
return minBufferDurationUs <= 0
|
return minBufferDurationUs <= 0
|
||||||
|| bufferedDurationUs >= minBufferDurationUs
|
|| bufferedDurationUs >= minBufferDurationUs
|
||||||
|| (!prioritizeTimeOverSizeThresholds
|
|| (!prioritizeTimeOverSizeThresholds
|
||||||
@ -441,7 +445,7 @@ public class DefaultLoadControl implements LoadControl {
|
|||||||
targetBufferBytesOverwrite == C.LENGTH_UNSET
|
targetBufferBytesOverwrite == C.LENGTH_UNSET
|
||||||
? DEFAULT_MIN_BUFFER_SIZE
|
? DEFAULT_MIN_BUFFER_SIZE
|
||||||
: targetBufferBytesOverwrite;
|
: targetBufferBytesOverwrite;
|
||||||
isBuffering = false;
|
isLoading = false;
|
||||||
if (resetAllocator) {
|
if (resetAllocator) {
|
||||||
allocator.reset();
|
allocator.reset();
|
||||||
}
|
}
|
||||||
|
@ -1647,10 +1647,20 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
}
|
}
|
||||||
// Renderers are ready and we're loading. Ask the LoadControl whether to transition.
|
// Renderers are ready and we're loading. Ask the LoadControl whether to transition.
|
||||||
MediaPeriodHolder loadingHolder = queue.getLoadingPeriod();
|
MediaPeriodHolder loadingHolder = queue.getLoadingPeriod();
|
||||||
|
int windowIndex =
|
||||||
|
playbackInfo.timeline.getPeriodByUid(queue.getPlayingPeriod().uid, period).windowIndex;
|
||||||
|
playbackInfo.timeline.getWindow(windowIndex, window);
|
||||||
|
long targetLiveOffsetUs =
|
||||||
|
window.isLive && window.isDynamic
|
||||||
|
? livePlaybackSpeedControl.getTargetLiveOffsetUs()
|
||||||
|
: C.TIME_UNSET;
|
||||||
boolean bufferedToEnd = loadingHolder.isFullyBuffered() && loadingHolder.info.isFinal;
|
boolean bufferedToEnd = loadingHolder.isFullyBuffered() && loadingHolder.info.isFinal;
|
||||||
return bufferedToEnd
|
return bufferedToEnd
|
||||||
|| loadControl.shouldStartPlayback(
|
|| loadControl.shouldStartPlayback(
|
||||||
getTotalBufferedDurationUs(), mediaClock.getPlaybackParameters().speed, rebuffering);
|
getTotalBufferedDurationUs(),
|
||||||
|
mediaClock.getPlaybackParameters().speed,
|
||||||
|
rebuffering,
|
||||||
|
targetLiveOffsetUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTimelineReady() {
|
private boolean isTimelineReady() {
|
||||||
|
@ -25,9 +25,7 @@ import com.google.android.exoplayer2.upstream.Allocator;
|
|||||||
*/
|
*/
|
||||||
public interface LoadControl {
|
public interface LoadControl {
|
||||||
|
|
||||||
/**
|
/** Called by the player when prepared with a new source. */
|
||||||
* Called by the player when prepared with a new source.
|
|
||||||
*/
|
|
||||||
void onPrepared();
|
void onPrepared();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -113,7 +111,11 @@ public interface LoadControl {
|
|||||||
* @param rebuffering Whether the player is rebuffering. A rebuffer is defined to be caused by
|
* @param rebuffering Whether the player is rebuffering. A rebuffer is defined to be caused by
|
||||||
* buffer depletion rather than a user action. Hence this parameter is false during initial
|
* buffer depletion rather than a user action. Hence this parameter is false during initial
|
||||||
* buffering and when buffering as a result of a seek operation.
|
* buffering and when buffering as a result of a seek operation.
|
||||||
|
* @param targetLiveOffsetUs The desired playback position offset to the live edge in
|
||||||
|
* microseconds, or {@link C#TIME_UNSET} if the media is not a live stream or no offset is
|
||||||
|
* configured.
|
||||||
* @return Whether playback should be allowed to start or resume.
|
* @return Whether playback should be allowed to start or resume.
|
||||||
*/
|
*/
|
||||||
boolean shouldStartPlayback(long bufferedDurationUs, float playbackSpeed, boolean rebuffering);
|
boolean shouldStartPlayback(
|
||||||
|
long bufferedDurationUs, float playbackSpeed, boolean rebuffering, long targetLiveOffsetUs);
|
||||||
}
|
}
|
||||||
|
@ -174,6 +174,17 @@ public class DefaultLoadControlTest {
|
|||||||
.isTrue();
|
.isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldContinueLoading_withNoSelectedTracks_returnsTrue() {
|
||||||
|
loadControl = builder.build();
|
||||||
|
loadControl.onTracksSelected(new Renderer[0], TrackGroupArray.EMPTY, new TrackSelectionArray());
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
loadControl.shouldContinueLoading(
|
||||||
|
/* playbackPositionUs= */ 0, /* bufferedDurationUs= */ 0, /* playbackSpeed= */ 1f))
|
||||||
|
.isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldNotContinueLoadingWithMaxBufferReached_inFastPlayback() {
|
public void shouldNotContinueLoadingWithMaxBufferReached_inFastPlayback() {
|
||||||
build();
|
build();
|
||||||
@ -185,21 +196,117 @@ public class DefaultLoadControlTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startsPlayback_whenMinBufferSizeReached() {
|
public void shouldStartPlayback_whenMinBufferSizeReached_returnsTrue() {
|
||||||
build();
|
build();
|
||||||
|
|
||||||
assertThat(loadControl.shouldStartPlayback(MIN_BUFFER_US, SPEED, /* rebuffering= */ false))
|
assertThat(
|
||||||
|
loadControl.shouldStartPlayback(
|
||||||
|
MIN_BUFFER_US,
|
||||||
|
SPEED,
|
||||||
|
/* rebuffering= */ false,
|
||||||
|
/* targetLiveOffsetUs= */ C.TIME_UNSET))
|
||||||
.isTrue();
|
.isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldContinueLoading_withNoSelectedTracks_returnsTrue() {
|
public void
|
||||||
loadControl = builder.build();
|
shouldStartPlayback_withoutTargetLiveOffset_returnsTrueWhenBufferForPlaybackReached() {
|
||||||
loadControl.onTracksSelected(new Renderer[0], TrackGroupArray.EMPTY, new TrackSelectionArray());
|
builder.setBufferDurationsMs(
|
||||||
|
/* minBufferMs= */ 5_000,
|
||||||
|
/* maxBufferMs= */ 20_000,
|
||||||
|
/* bufferForPlaybackMs= */ 3_000,
|
||||||
|
/* bufferForPlaybackAfterRebufferMs= */ 4_000);
|
||||||
|
build();
|
||||||
|
|
||||||
assertThat(
|
assertThat(
|
||||||
loadControl.shouldContinueLoading(
|
loadControl.shouldStartPlayback(
|
||||||
/* playbackPositionUs= */ 0, /* bufferedDurationUs= */ 0, /* playbackSpeed= */ 1f))
|
/* bufferedDurationUs= */ 2_999_999,
|
||||||
|
SPEED,
|
||||||
|
/* rebuffering= */ false,
|
||||||
|
/* targetLiveOffsetUs= */ C.TIME_UNSET))
|
||||||
|
.isFalse();
|
||||||
|
assertThat(
|
||||||
|
loadControl.shouldStartPlayback(
|
||||||
|
/* bufferedDurationUs= */ 3_000_000,
|
||||||
|
SPEED,
|
||||||
|
/* rebuffering= */ false,
|
||||||
|
/* targetLiveOffsetUs= */ C.TIME_UNSET))
|
||||||
|
.isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldStartPlayback_withTargetLiveOffset_returnsTrueWhenHalfLiveOffsetReached() {
|
||||||
|
builder.setBufferDurationsMs(
|
||||||
|
/* minBufferMs= */ 5_000,
|
||||||
|
/* maxBufferMs= */ 20_000,
|
||||||
|
/* bufferForPlaybackMs= */ 3_000,
|
||||||
|
/* bufferForPlaybackAfterRebufferMs= */ 4_000);
|
||||||
|
build();
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
loadControl.shouldStartPlayback(
|
||||||
|
/* bufferedDurationUs= */ 499_999,
|
||||||
|
SPEED,
|
||||||
|
/* rebuffering= */ true,
|
||||||
|
/* targetLiveOffsetUs= */ 1_000_000))
|
||||||
|
.isFalse();
|
||||||
|
assertThat(
|
||||||
|
loadControl.shouldStartPlayback(
|
||||||
|
/* bufferedDurationUs= */ 500_000,
|
||||||
|
SPEED,
|
||||||
|
/* rebuffering= */ true,
|
||||||
|
/* targetLiveOffsetUs= */ 1_000_000))
|
||||||
|
.isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
shouldStartPlayback_afterRebuffer_withoutTargetLiveOffset_whenBufferForPlaybackAfterRebufferReached() {
|
||||||
|
builder.setBufferDurationsMs(
|
||||||
|
/* minBufferMs= */ 5_000,
|
||||||
|
/* maxBufferMs= */ 20_000,
|
||||||
|
/* bufferForPlaybackMs= */ 3_000,
|
||||||
|
/* bufferForPlaybackAfterRebufferMs= */ 4_000);
|
||||||
|
build();
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
loadControl.shouldStartPlayback(
|
||||||
|
/* bufferedDurationUs= */ 3_999_999,
|
||||||
|
SPEED,
|
||||||
|
/* rebuffering= */ true,
|
||||||
|
/* targetLiveOffsetUs= */ C.TIME_UNSET))
|
||||||
|
.isFalse();
|
||||||
|
assertThat(
|
||||||
|
loadControl.shouldStartPlayback(
|
||||||
|
/* bufferedDurationUs= */ 4_000_000,
|
||||||
|
SPEED,
|
||||||
|
/* rebuffering= */ true,
|
||||||
|
/* targetLiveOffsetUs= */ C.TIME_UNSET))
|
||||||
|
.isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldStartPlayback_afterRebuffer_withTargetLiveOffset_whenHalfLiveOffsetReached() {
|
||||||
|
builder.setBufferDurationsMs(
|
||||||
|
/* minBufferMs= */ 5_000,
|
||||||
|
/* maxBufferMs= */ 20_000,
|
||||||
|
/* bufferForPlaybackMs= */ 3_000,
|
||||||
|
/* bufferForPlaybackAfterRebufferMs= */ 4_000);
|
||||||
|
build();
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
loadControl.shouldStartPlayback(
|
||||||
|
/* bufferedDurationUs= */ 499_999,
|
||||||
|
SPEED,
|
||||||
|
/* rebuffering= */ true,
|
||||||
|
/* targetLiveOffsetUs= */ 1_000_000))
|
||||||
|
.isFalse();
|
||||||
|
assertThat(
|
||||||
|
loadControl.shouldStartPlayback(
|
||||||
|
/* bufferedDurationUs= */ 500_000,
|
||||||
|
SPEED,
|
||||||
|
/* rebuffering= */ true,
|
||||||
|
/* targetLiveOffsetUs= */ 1_000_000))
|
||||||
.isTrue();
|
.isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4605,7 +4605,10 @@ public final class ExoPlayerTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldStartPlayback(
|
public boolean shouldStartPlayback(
|
||||||
long bufferedDurationUs, float playbackSpeed, boolean rebuffering) {
|
long bufferedDurationUs,
|
||||||
|
float playbackSpeed,
|
||||||
|
boolean rebuffering,
|
||||||
|
long targetLiveOffsetUs) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -4649,7 +4652,10 @@ public final class ExoPlayerTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldStartPlayback(
|
public boolean shouldStartPlayback(
|
||||||
long bufferedDurationUs, float playbackSpeed, boolean rebuffering) {
|
long bufferedDurationUs,
|
||||||
|
float playbackSpeed,
|
||||||
|
boolean rebuffering,
|
||||||
|
long targetLiveOffsetUs) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -4724,7 +4730,10 @@ public final class ExoPlayerTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldStartPlayback(
|
public boolean shouldStartPlayback(
|
||||||
long bufferedDurationUs, float playbackSpeed, boolean rebuffering) {
|
long bufferedDurationUs,
|
||||||
|
float playbackSpeed,
|
||||||
|
boolean rebuffering,
|
||||||
|
long targetLiveOffsetUs) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user