diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 49c63a0efe..0b8a5ffc15 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -43,6 +43,12 @@
`MimeTypes.APPLICATION_MEDIA3_CUES`.
* Add `PngExtractor` that sends and reads a whole png file into the the
`TrackOutput` as one sample.
+ * Enhance `SequenceableLoader.continueLoading(long)` method in the
+ `SequenceableLoader` interface to
+ `SequenceableLoader.continueLoading(LoadingInfo loadingInfo)`.
+ `LoadingInfo` contains additional parameters, including `playbackSpeed`
+ and `lastRebufferRealtimeMs` in addition to the existing
+ `playbackPositionUs`.
* Transformer:
* Parse EXIF rotation data for image inputs.
* Remove `TransformationRequest.HdrMode` annotation type and its
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java
index 0c07301418..489e77da17 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java
@@ -218,6 +218,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
private boolean pauseAtEndOfWindow;
private boolean pendingPauseAtEndOfPeriod;
private boolean isRebuffering;
+ private long lastRebufferRealtimeMs;
private boolean shouldContinueLoading;
private @Player.RepeatMode int repeatMode;
private boolean shuffleModeEnabled;
@@ -267,6 +268,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
this.clock = clock;
playbackMaybeBecameStuckAtMs = C.TIME_UNSET;
+ lastRebufferRealtimeMs = C.TIME_UNSET;
backBufferDurationUs = loadControl.getBackBufferDurationUs();
retainBackBufferFromKeyframe = loadControl.retainBackBufferFromKeyframe();
@@ -852,7 +854,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
playbackInfoUpdate.incrementPendingOperationAcks(operationAck ? 1 : 0);
playbackInfoUpdate.setPlayWhenReadyChangeReason(reason);
playbackInfo = playbackInfo.copyWithPlayWhenReady(playWhenReady, playbackSuppressionReason);
- isRebuffering = false;
+ updateRebufferingState(/* isRebuffering= */ false, /* resetLastRebufferRealtimeMs= */ false);
notifyTrackSelectionPlayWhenReadyChanged(playWhenReady);
if (!shouldPlayWhenReady()) {
stopRenderers();
@@ -931,7 +933,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
private void startRenderers() throws ExoPlaybackException {
- isRebuffering = false;
+ updateRebufferingState(/* isRebuffering= */ false, /* resetLastRebufferRealtimeMs= */ false);
mediaClock.start();
for (Renderer renderer : renderers) {
if (isRendererEnabled(renderer)) {
@@ -1120,7 +1122,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
} else if (playbackInfo.playbackState == Player.STATE_READY
&& !(enabledRendererCount == 0 ? isTimelineReady() : renderersAllowPlayback)) {
- isRebuffering = shouldPlayWhenReady();
+ updateRebufferingState(
+ /* isRebuffering= */ shouldPlayWhenReady(), /* resetLastRebufferRealtimeMs= */ false);
setState(Player.STATE_BUFFERING);
if (isRebuffering) {
notifyTrackSelectionRebuffer();
@@ -1334,7 +1337,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
boolean forceBufferingState)
throws ExoPlaybackException {
stopRenderers();
- isRebuffering = false;
+ updateRebufferingState(/* isRebuffering= */ false, /* resetLastRebufferRealtimeMs= */ true);
if (forceBufferingState || playbackInfo.playbackState == Player.STATE_READY) {
setState(Player.STATE_BUFFERING);
}
@@ -1475,7 +1478,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
boolean resetError) {
handler.removeMessages(MSG_DO_SOME_WORK);
pendingRecoverableRendererError = null;
- isRebuffering = false;
+ updateRebufferingState(/* isRebuffering= */ false, /* resetLastRebufferRealtimeMs= */ true);
mediaClock.stop();
rendererPositionUs = MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US;
for (Renderer renderer : renderers) {
@@ -2436,7 +2439,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
private void maybeContinueLoading() {
shouldContinueLoading = shouldContinueLoading();
if (shouldContinueLoading) {
- queue.getLoadingPeriod().continueLoading(rendererPositionUs);
+ queue
+ .getLoadingPeriod()
+ .continueLoading(
+ rendererPositionUs, mediaClock.getPlaybackParameters().speed, lastRebufferRealtimeMs);
}
updateIsLoading();
}
@@ -2907,6 +2913,23 @@ import java.util.concurrent.atomic.AtomicBoolean;
return timeline.isEmpty() || timeline.getPeriodByUid(periodId.periodUid, period).isPlaceholder;
}
+ /**
+ * Updates the {@link #isRebuffering} state and the timestamp of the last rebuffering event.
+ *
+ * @param isRebuffering A boolean indicating whether the media playback is currently rebuffering.
+ * @param resetLastRebufferRealtimeMs A boolean indicating whether {@link #lastRebufferRealtimeMs}
+ * should be reset.
+ * If set to {@code true}, the method resets the {@link #lastRebufferRealtimeMs} to {@link
+ * C#TIME_UNSET}.
+ * If set to {@code false}, the method updates the {@link #lastRebufferRealtimeMs} with the
+ * current value of {@link Clock#elapsedRealtime()}.
+ */
+ private void updateRebufferingState(boolean isRebuffering, boolean resetLastRebufferRealtimeMs) {
+ this.isRebuffering = isRebuffering;
+ this.lastRebufferRealtimeMs =
+ resetLastRebufferRealtimeMs ? C.TIME_UNSET : clock.elapsedRealtime();
+ }
+
/**
* Updates pending message to a new timeline.
*
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/LoadingInfo.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/LoadingInfo.java
new file mode 100644
index 0000000000..82025e6c67
--- /dev/null
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/LoadingInfo.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.media3.exoplayer;
+
+import static androidx.media3.common.util.Assertions.checkArgument;
+
+import android.os.SystemClock;
+import androidx.media3.common.C;
+import androidx.media3.common.util.UnstableApi;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+
+/** Information about the player state when loading is started or continued. */
+@UnstableApi
+public final class LoadingInfo {
+
+ /** A builder for {@link LoadingInfo} instances. */
+ public static final class Builder {
+ private long playbackPositionUs;
+ private float playbackSpeed;
+ private long lastRebufferRealtimeMs;
+
+ /** Creates a new instance with default values. */
+ public Builder() {
+ this.playbackPositionUs = C.TIME_UNSET;
+ this.playbackSpeed = C.RATE_UNSET;
+ this.lastRebufferRealtimeMs = C.TIME_UNSET;
+ }
+
+ private Builder(LoadingInfo loadingInfo) {
+ this.playbackPositionUs = loadingInfo.playbackPositionUs;
+ this.playbackSpeed = loadingInfo.playbackSpeed;
+ this.lastRebufferRealtimeMs = loadingInfo.lastRebufferRealtimeMs;
+ }
+
+ /** Sets {@link LoadingInfo#playbackPositionUs}. The default is {@link C#TIME_UNSET} */
+ @CanIgnoreReturnValue
+ public Builder setPlaybackPositionUs(long playbackPositionUs) {
+ this.playbackPositionUs = playbackPositionUs;
+ return this;
+ }
+
+ /**
+ * Sets {@link LoadingInfo#playbackSpeed}. The default is {@link C#RATE_UNSET}
+ *
+ * @throws IllegalArgumentException If {@code playbackSpeed} is not equal to {@link
+ * C#RATE_UNSET} and is non-positive.
+ */
+ @CanIgnoreReturnValue
+ public Builder setPlaybackSpeed(float playbackSpeed) {
+ checkArgument(playbackSpeed > 0 || playbackSpeed == C.RATE_UNSET);
+ this.playbackSpeed = playbackSpeed;
+ return this;
+ }
+
+ /**
+ * Sets {@link LoadingInfo#lastRebufferRealtimeMs}. The default is {@link C#TIME_UNSET}
+ *
+ * @throws IllegalArgumentException If {@code lastRebufferRealtimeMs} is not equal to {@link
+ * C#TIME_UNSET} and is negative.
+ */
+ @CanIgnoreReturnValue
+ public Builder setLastRebufferRealtimeMs(long lastRebufferRealtimeMs) {
+ checkArgument(lastRebufferRealtimeMs >= 0 || lastRebufferRealtimeMs == C.TIME_UNSET);
+ this.lastRebufferRealtimeMs = lastRebufferRealtimeMs;
+ return this;
+ }
+
+ /** Returns a new {@link LoadingInfo} instance with the current builder values. */
+ public LoadingInfo build() {
+ return new LoadingInfo(this);
+ }
+ }
+
+ /**
+ * The current playback position in microseconds, or {@link C#TIME_UNSET} if unset. If playback of
+ * the period to which this loading info belongs has not yet started, the value will be the
+ * starting position in the period minus the duration of any media in previous periods still to be
+ * played.
+ */
+ public final long playbackPositionUs;
+
+ /**
+ * The playback speed indicating the current rate of playback, or {@link C#RATE_UNSET} if playback
+ * speed is not known when the load is started or continued.
+ */
+ public final float playbackSpeed;
+
+ /**
+ * Sets the time at which the last rebuffering occurred, in milliseconds since boot including time
+ * spent in sleep.
+ *
+ *
The time base used is the same as that measured by {@link SystemClock#elapsedRealtime}.
+ *
+ *
Note: If rebuffer events are not known when the load is started or continued, or if
+ * no rebuffering has occurred, or if there have been any user interactions such as seeking or
+ * stopping the player, the value will be set to {@link C#TIME_UNSET}.
+ */
+ public final long lastRebufferRealtimeMs;
+
+ private LoadingInfo(Builder builder) {
+ this.playbackPositionUs = builder.playbackPositionUs;
+ this.playbackSpeed = builder.playbackSpeed;
+ this.lastRebufferRealtimeMs = builder.lastRebufferRealtimeMs;
+ }
+
+ /** Creates a new {@link Builder}, copying the initial values from this instance. */
+ public LoadingInfo.Builder buildUpon() {
+ return new LoadingInfo.Builder(this);
+ }
+}
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaPeriodHolder.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaPeriodHolder.java
index 8a2d3aa419..0d2427a48d 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaPeriodHolder.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaPeriodHolder.java
@@ -222,11 +222,21 @@ import androidx.media3.exoplayer.upstream.Allocator;
* this is the loading media period.
*
* @param rendererPositionUs The load position in renderer time, in microseconds.
+ * @param playbackSpeed The playback speed indicating the current rate of playback.
+ * @param lastRebufferRealtimeMs The time at which the last rebuffering occurred, in milliseconds
+ * since boot including time spent in sleep. The time base used is the same as that measured
+ * by {@link android.os.SystemClock#elapsedRealtime}.
*/
- public void continueLoading(long rendererPositionUs) {
+ public void continueLoading(
+ long rendererPositionUs, float playbackSpeed, long lastRebufferRealtimeMs) {
Assertions.checkState(isLoadingMediaPeriod());
long loadingPeriodPositionUs = toPeriodTime(rendererPositionUs);
- mediaPeriod.continueLoading(loadingPeriodPositionUs);
+ mediaPeriod.continueLoading(
+ new LoadingInfo.Builder()
+ .setPlaybackPositionUs(loadingPeriodPositionUs)
+ .setPlaybackSpeed(playbackSpeed)
+ .setLastRebufferRealtimeMs(lastRebufferRealtimeMs)
+ .build());
}
/**
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MetadataRetriever.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MetadataRetriever.java
index 9a58981f5d..32044335a1 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MetadataRetriever.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MetadataRetriever.java
@@ -164,7 +164,8 @@ public final class MetadataRetriever {
}
return true;
case MESSAGE_CONTINUE_LOADING:
- checkNotNull(mediaPeriod).continueLoading(/* positionUs= */ 0);
+ checkNotNull(mediaPeriod)
+ .continueLoading(new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
return true;
case MESSAGE_RELEASE:
if (mediaPeriod != null) {
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/DownloadHelper.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/DownloadHelper.java
index ce399f484a..a44a58fe5a 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/DownloadHelper.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/DownloadHelper.java
@@ -39,6 +39,7 @@ import androidx.media3.common.util.Util;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.TransferListener;
import androidx.media3.exoplayer.ExoPlaybackException;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.Renderer;
import androidx.media3.exoplayer.RendererCapabilities;
import androidx.media3.exoplayer.RenderersFactory;
@@ -896,7 +897,7 @@ public final class DownloadHelper {
case MESSAGE_CONTINUE_LOADING:
MediaPeriod mediaPeriod = (MediaPeriod) msg.obj;
if (pendingMediaPeriods.contains(mediaPeriod)) {
- mediaPeriod.continueLoading(/* positionUs= */ 0);
+ mediaPeriod.continueLoading(new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
}
return true;
case MESSAGE_RELEASE:
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ClippingMediaPeriod.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ClippingMediaPeriod.java
index 8acbc4044e..07c2fc65d8 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ClippingMediaPeriod.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ClippingMediaPeriod.java
@@ -25,6 +25,7 @@ import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.exoplayer.FormatHolder;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.source.ClippingMediaSource.IllegalClippingException;
import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
@@ -222,8 +223,8 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
}
@Override
- public boolean continueLoading(long positionUs) {
- return mediaPeriod.continueLoading(positionUs);
+ public boolean continueLoading(LoadingInfo loadingInfo) {
+ return mediaPeriod.continueLoading(loadingInfo);
}
@Override
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/CompositeSequenceableLoader.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/CompositeSequenceableLoader.java
index d072966548..cc97d21f5e 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/CompositeSequenceableLoader.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/CompositeSequenceableLoader.java
@@ -19,6 +19,7 @@ import static java.lang.Math.min;
import androidx.media3.common.C;
import androidx.media3.common.util.UnstableApi;
+import androidx.media3.exoplayer.LoadingInfo;
/** A {@link SequenceableLoader} that encapsulates multiple other {@link SequenceableLoader}s. */
@UnstableApi
@@ -62,7 +63,7 @@ public class CompositeSequenceableLoader implements SequenceableLoader {
}
@Override
- public boolean continueLoading(long positionUs) {
+ public boolean continueLoading(LoadingInfo loadingInfo) {
boolean madeProgress = false;
boolean madeProgressThisIteration;
do {
@@ -75,9 +76,9 @@ public class CompositeSequenceableLoader implements SequenceableLoader {
long loaderNextLoadPositionUs = loader.getNextLoadPositionUs();
boolean isLoaderBehind =
loaderNextLoadPositionUs != C.TIME_END_OF_SOURCE
- && loaderNextLoadPositionUs <= positionUs;
+ && loaderNextLoadPositionUs <= loadingInfo.playbackPositionUs;
if (loaderNextLoadPositionUs == nextLoadPositionUs || isLoaderBehind) {
- madeProgressThisIteration |= loader.continueLoading(positionUs);
+ madeProgressThisIteration |= loader.continueLoading(loadingInfo);
}
}
madeProgress |= madeProgressThisIteration;
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/FilteringMediaSource.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/FilteringMediaSource.java
index 4b170567d2..21bff1344f 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/FilteringMediaSource.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/FilteringMediaSource.java
@@ -23,6 +23,7 @@ import androidx.media3.common.StreamKey;
import androidx.media3.common.TrackGroup;
import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.UnstableApi;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
import androidx.media3.exoplayer.upstream.Allocator;
@@ -155,8 +156,8 @@ public class FilteringMediaSource extends WrappingMediaSource {
}
@Override
- public boolean continueLoading(long positionUs) {
- return mediaPeriod.continueLoading(positionUs);
+ public boolean continueLoading(LoadingInfo loadingInfo) {
+ return mediaPeriod.continueLoading(loadingInfo);
}
@Override
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MaskingMediaPeriod.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MaskingMediaPeriod.java
index b4cda271bf..8be27948a7 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MaskingMediaPeriod.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MaskingMediaPeriod.java
@@ -23,6 +23,7 @@ import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.UnstableApi;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId;
import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
@@ -224,8 +225,8 @@ public final class MaskingMediaPeriod implements MediaPeriod, MediaPeriod.Callba
}
@Override
- public boolean continueLoading(long positionUs) {
- return mediaPeriod != null && mediaPeriod.continueLoading(positionUs);
+ public boolean continueLoading(LoadingInfo loadingInfo) {
+ return mediaPeriod != null && mediaPeriod.continueLoading(loadingInfo);
}
@Override
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MediaPeriod.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MediaPeriod.java
index 62b4e2ccc7..2ab6a4764b 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MediaPeriod.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MediaPeriod.java
@@ -22,6 +22,7 @@ import androidx.media3.common.TrackGroup;
import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.exoplayer.ExoPlayer;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.source.MediaSource.MediaSourceCaller;
import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
@@ -231,14 +232,12 @@ public interface MediaPeriod extends SequenceableLoader {
* called when the period is permitted to continue loading data. A period may do this both during
* and after preparation.
*
- * @param positionUs The current playback position in microseconds. If playback of this period has
- * not yet started, the value will be the starting position in this period minus the duration
- * of any media in previous periods still to be played.
+ * @param loadingInfo The {@link LoadingInfo} when attempting to continue loading.
* @return True if progress was made, meaning that {@link #getNextLoadPositionUs()} will return a
* different value than prior to the call. False otherwise.
*/
@Override
- boolean continueLoading(long positionUs);
+ boolean continueLoading(LoadingInfo loadingInfo);
/** Returns whether the media period is currently loading. */
@Override
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MergingMediaPeriod.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MergingMediaPeriod.java
index 10597e654d..858b412034 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MergingMediaPeriod.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MergingMediaPeriod.java
@@ -26,6 +26,7 @@ import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.NullableType;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.exoplayer.FormatHolder;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.source.chunk.Chunk;
import androidx.media3.exoplayer.source.chunk.MediaChunk;
@@ -192,16 +193,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
@Override
- public boolean continueLoading(long positionUs) {
+ public boolean continueLoading(LoadingInfo loadingInfo) {
if (!childrenPendingPreparation.isEmpty()) {
// Preparation is still going on.
int childrenPendingPreparationSize = childrenPendingPreparation.size();
for (int i = 0; i < childrenPendingPreparationSize; i++) {
- childrenPendingPreparation.get(i).continueLoading(positionUs);
+ childrenPendingPreparation.get(i).continueLoading(loadingInfo);
}
return false;
} else {
- return compositeSequenceableLoader.continueLoading(positionUs);
+ return compositeSequenceableLoader.continueLoading(loadingInfo);
}
}
@@ -406,8 +407,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
@Override
- public boolean continueLoading(long positionUs) {
- return mediaPeriod.continueLoading(positionUs - timeOffsetUs);
+ public boolean continueLoading(LoadingInfo loadingInfo) {
+ return mediaPeriod.continueLoading(
+ loadingInfo
+ .buildUpon()
+ .setPlaybackPositionUs(loadingInfo.playbackPositionUs - timeOffsetUs)
+ .build());
}
@Override
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ProgressiveMediaPeriod.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ProgressiveMediaPeriod.java
index fbc2c24771..55e183477e 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ProgressiveMediaPeriod.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ProgressiveMediaPeriod.java
@@ -40,6 +40,7 @@ import androidx.media3.datasource.DataSpec;
import androidx.media3.datasource.StatsDataSource;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.exoplayer.FormatHolder;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
import androidx.media3.exoplayer.drm.DrmSessionManager;
@@ -343,7 +344,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
@Override
- public boolean continueLoading(long playbackPositionUs) {
+ public boolean continueLoading(LoadingInfo loadingInfo) {
if (loadingFinished
|| loader.hasFatalError()
|| pendingDeferredRetry
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SequenceableLoader.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SequenceableLoader.java
index 8fae8f0d3e..4d19dd3fc6 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SequenceableLoader.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SequenceableLoader.java
@@ -17,6 +17,7 @@ package androidx.media3.exoplayer.source;
import androidx.media3.common.C;
import androidx.media3.common.util.UnstableApi;
+import androidx.media3.exoplayer.LoadingInfo;
// TODO: Clarify the requirements for implementing this interface [Internal ref: b/36250203].
/** A loader that can proceed in approximate synchronization with other loaders. */
@@ -27,8 +28,8 @@ public interface SequenceableLoader {
interface Callback {
/**
- * Called by the loader to indicate that it wishes for its {@link #continueLoading(long)} method
- * to be called when it can continue to load data. Called on the playback thread.
+ * Called by the loader to indicate that it wishes for its {@link #continueLoading(LoadingInfo)}
+ * method to be called when it can continue to load data. Called on the playback thread.
*/
void onContinueLoadingRequested(T source);
}
@@ -47,13 +48,11 @@ public interface SequenceableLoader {
/**
* Attempts to continue loading.
*
- * @param positionUs The current playback position in microseconds. If playback of the period to
- * which this loader belongs has not yet started, the value will be the starting position in
- * the period minus the duration of any media in previous periods still to be played.
+ * @param loadingInfo The {@link LoadingInfo} when attempting to continue loading.
* @return True if progress was made, meaning that {@link #getNextLoadPositionUs()} will return a
* different value than prior to the call. False otherwise.
*/
- boolean continueLoading(long positionUs);
+ boolean continueLoading(LoadingInfo loadingInfo);
/** Returns whether the loader is currently loading. */
boolean isLoading();
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SilenceMediaSource.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SilenceMediaSource.java
index 9e9b1fe151..136be3dab4 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SilenceMediaSource.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SilenceMediaSource.java
@@ -34,6 +34,7 @@ import androidx.media3.common.util.Util;
import androidx.media3.datasource.TransferListener;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.exoplayer.FormatHolder;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
import androidx.media3.exoplayer.upstream.Allocator;
@@ -257,7 +258,7 @@ public final class SilenceMediaSource extends BaseMediaSource {
}
@Override
- public boolean continueLoading(long positionUs) {
+ public boolean continueLoading(LoadingInfo loadingInfo) {
return false;
}
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SingleSampleMediaPeriod.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SingleSampleMediaPeriod.java
index 77ed459cad..9348819a8c 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SingleSampleMediaPeriod.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SingleSampleMediaPeriod.java
@@ -31,6 +31,7 @@ import androidx.media3.datasource.StatsDataSource;
import androidx.media3.datasource.TransferListener;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.exoplayer.FormatHolder;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.source.MediaSourceEventListener.EventDispatcher;
import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
@@ -145,7 +146,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
@Override
- public boolean continueLoading(long positionUs) {
+ public boolean continueLoading(LoadingInfo loadingInfo) {
if (loadingFinished || loader.isLoading() || loader.hasFatalError()) {
return false;
}
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ads/ServerSideAdInsertionMediaSource.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ads/ServerSideAdInsertionMediaSource.java
index 98db8c05d8..3ed590e3ea 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ads/ServerSideAdInsertionMediaSource.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ads/ServerSideAdInsertionMediaSource.java
@@ -42,6 +42,7 @@ import androidx.media3.common.util.Util;
import androidx.media3.datasource.TransferListener;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.exoplayer.FormatHolder;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.drm.DrmSession;
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
@@ -741,7 +742,7 @@ public final class ServerSideAdInsertionMediaSource extends BaseMediaSource
return actualMediaPeriod.getStreamKeys(trackSelections);
}
- public boolean continueLoading(MediaPeriodImpl mediaPeriod, long positionUs) {
+ public boolean continueLoading(MediaPeriodImpl mediaPeriod, LoadingInfo loadingInfo) {
@Nullable MediaPeriodImpl loadingPeriod = this.loadingPeriod;
if (loadingPeriod != null && !mediaPeriod.equals(loadingPeriod)) {
for (Pair loadData : activeLoads.values()) {
@@ -754,8 +755,9 @@ public final class ServerSideAdInsertionMediaSource extends BaseMediaSource
}
this.loadingPeriod = mediaPeriod;
long actualPlaybackPositionUs =
- getStreamPositionUsWithNotYetStartedHandling(mediaPeriod, positionUs);
- return actualMediaPeriod.continueLoading(actualPlaybackPositionUs);
+ getStreamPositionUsWithNotYetStartedHandling(mediaPeriod, loadingInfo.playbackPositionUs);
+ return actualMediaPeriod.continueLoading(
+ loadingInfo.buildUpon().setPlaybackPositionUs(actualPlaybackPositionUs).build());
}
public boolean isLoading(MediaPeriodImpl mediaPeriod) {
@@ -1209,8 +1211,8 @@ public final class ServerSideAdInsertionMediaSource extends BaseMediaSource
}
@Override
- public boolean continueLoading(long positionUs) {
- return sharedPeriod.continueLoading(/* mediaPeriod= */ this, positionUs);
+ public boolean continueLoading(LoadingInfo loadingInfo) {
+ return sharedPeriod.continueLoading(/* mediaPeriod= */ this, loadingInfo);
}
@Override
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/chunk/ChunkSampleStream.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/chunk/ChunkSampleStream.java
index 84a62381af..4acdbb191f 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/chunk/ChunkSampleStream.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/chunk/ChunkSampleStream.java
@@ -28,6 +28,7 @@ import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.exoplayer.FormatHolder;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.drm.DrmSession;
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
@@ -561,7 +562,7 @@ public class ChunkSampleStream
// SequenceableLoader implementation
@Override
- public boolean continueLoading(long positionUs) {
+ public boolean continueLoading(LoadingInfo loadingInfo) {
if (loadingFinished || loader.isLoading() || loader.hasFatalError()) {
return false;
}
@@ -576,7 +577,8 @@ public class ChunkSampleStream
chunkQueue = readOnlyMediaChunks;
loadPositionUs = getLastMediaChunk().endTimeUs;
}
- chunkSource.getNextChunk(positionUs, loadPositionUs, chunkQueue, nextChunkHolder);
+ chunkSource.getNextChunk(
+ loadingInfo.playbackPositionUs, loadPositionUs, chunkQueue, nextChunkHolder);
boolean endOfStream = nextChunkHolder.endOfStream;
@Nullable Chunk loadable = nextChunkHolder.chunk;
nextChunkHolder.clear();
diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java
index ca860ab522..36c903f8a9 100644
--- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java
+++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java
@@ -8679,7 +8679,7 @@ public final class ExoPlayerTest {
}
@Override
- public boolean continueLoading(long positionUs) {
+ public boolean continueLoading(LoadingInfo loadingInfo) {
allocations.add(allocator.allocate());
callback.onContinueLoadingRequested(this);
return true;
@@ -8744,8 +8744,8 @@ public final class ExoPlayerTest {
private final Loader loader = new Loader("ExoPlayerTest");
@Override
- public boolean continueLoading(long positionUs) {
- super.continueLoading(positionUs);
+ public boolean continueLoading(LoadingInfo loadingInfo) {
+ super.continueLoading(loadingInfo);
if (!loader.isLoading()) {
loader.startLoading(
loadable, new FakeLoaderCallback(), /* defaultMinRetryCount= */ 1);
diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ClippingMediaPeriodTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ClippingMediaPeriodTest.java
index cc9804be59..fc85afcf74 100644
--- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ClippingMediaPeriodTest.java
+++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ClippingMediaPeriodTest.java
@@ -25,6 +25,7 @@ import androidx.media3.common.Format;
import androidx.media3.common.TrackGroup;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.exoplayer.FormatHolder;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
import androidx.media3.exoplayer.drm.DrmSessionManager;
import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
@@ -116,7 +117,8 @@ public class ClippingMediaPeriodTest {
@Override
public void onContinueLoadingRequested(MediaPeriod source) {
- clippingMediaPeriod.continueLoading(/* positionUs= */ 0);
+ clippingMediaPeriod.continueLoading(
+ new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
}
},
/* positionUs= */ 0);
diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/CompositeSequenceableLoaderTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/CompositeSequenceableLoaderTest.java
index 20557f816f..436d8c0b3f 100644
--- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/CompositeSequenceableLoaderTest.java
+++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/CompositeSequenceableLoaderTest.java
@@ -18,6 +18,7 @@ package androidx.media3.exoplayer.source;
import static com.google.common.truth.Truth.assertThat;
import androidx.media3.common.C;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -130,9 +131,9 @@ public final class CompositeSequenceableLoaderTest {
}
/**
- * Tests that {@link CompositeSequenceableLoader#continueLoading(long)} only allows the loader
- * with minimum next load position to continue loading if next load positions are not behind
- * current playback position.
+ * Tests that {@link CompositeSequenceableLoader#continueLoading(LoadingInfo)} only allows the
+ * loader with minimum next load position to continue loading if next load positions are not
+ * behind current playback position.
*/
@Test
public void continueLoadingOnlyAllowFurthestBehindLoaderToLoadIfNotBehindPlaybackPosition() {
@@ -142,15 +143,16 @@ public final class CompositeSequenceableLoaderTest {
new FakeSequenceableLoader(/* bufferedPositionUs */ 1001, /* nextLoadPositionUs */ 2001);
CompositeSequenceableLoader compositeSequenceableLoader =
new CompositeSequenceableLoader(new SequenceableLoader[] {loader1, loader2});
- compositeSequenceableLoader.continueLoading(100);
+ compositeSequenceableLoader.continueLoading(
+ new LoadingInfo.Builder().setPlaybackPositionUs(100).build());
assertThat(loader1.numInvocations).isEqualTo(1);
assertThat(loader2.numInvocations).isEqualTo(0);
}
/**
- * Tests that {@link CompositeSequenceableLoader#continueLoading(long)} allows all loaders with
- * next load position behind current playback position to continue loading.
+ * Tests that {@link CompositeSequenceableLoader#continueLoading(LoadingInfo)} allows all loaders
+ * with next load position behind current playback position to continue loading.
*/
@Test
public void continueLoadingReturnAllowAllLoadersBehindPlaybackPositionToLoad() {
@@ -162,7 +164,8 @@ public final class CompositeSequenceableLoaderTest {
new FakeSequenceableLoader(/* bufferedPositionUs */ 1002, /* nextLoadPositionUs */ 2002);
CompositeSequenceableLoader compositeSequenceableLoader =
new CompositeSequenceableLoader(new SequenceableLoader[] {loader1, loader2, loader3});
- compositeSequenceableLoader.continueLoading(3000);
+ compositeSequenceableLoader.continueLoading(
+ new LoadingInfo.Builder().setPlaybackPositionUs(3000).build());
assertThat(loader1.numInvocations).isEqualTo(1);
assertThat(loader2.numInvocations).isEqualTo(1);
@@ -170,8 +173,8 @@ public final class CompositeSequenceableLoaderTest {
}
/**
- * Tests that {@link CompositeSequenceableLoader#continueLoading(long)} does not allow loader with
- * next load position at end-of-source to continue loading.
+ * Tests that {@link CompositeSequenceableLoader#continueLoading(LoadingInfo)} does not allow
+ * loader with next load position at end-of-source to continue loading.
*/
@Test
public void continueLoadingOnlyNotAllowEndOfSourceLoaderToLoad() {
@@ -183,16 +186,17 @@ public final class CompositeSequenceableLoaderTest {
/* bufferedPositionUs */ 1001, /* nextLoadPositionUs */ C.TIME_END_OF_SOURCE);
CompositeSequenceableLoader compositeSequenceableLoader =
new CompositeSequenceableLoader(new SequenceableLoader[] {loader1, loader2});
- compositeSequenceableLoader.continueLoading(3000);
+ compositeSequenceableLoader.continueLoading(
+ new LoadingInfo.Builder().setPlaybackPositionUs(3000).build());
assertThat(loader1.numInvocations).isEqualTo(0);
assertThat(loader2.numInvocations).isEqualTo(0);
}
/**
- * Tests that {@link CompositeSequenceableLoader#continueLoading(long)} returns true if the loader
- * with minimum next load position can make progress if next load positions are not behind current
- * playback position.
+ * Tests that {@link CompositeSequenceableLoader#continueLoading(LoadingInfo)} returns true if the
+ * loader with minimum next load position can make progress if next load positions are not behind
+ * current playback position.
*/
@Test
public void continueLoadingReturnTrueIfFurthestBehindLoaderCanMakeProgress() {
@@ -205,13 +209,16 @@ public final class CompositeSequenceableLoaderTest {
CompositeSequenceableLoader compositeSequenceableLoader =
new CompositeSequenceableLoader(new SequenceableLoader[] {loader1, loader2});
- assertThat(compositeSequenceableLoader.continueLoading(100)).isTrue();
+ assertThat(
+ compositeSequenceableLoader.continueLoading(
+ new LoadingInfo.Builder().setPlaybackPositionUs(100).build()))
+ .isTrue();
}
/**
- * Tests that {@link CompositeSequenceableLoader#continueLoading(long)} returns true if any loader
- * that are behind current playback position can make progress, even if it is not the one with
- * minimum next load position.
+ * Tests that {@link CompositeSequenceableLoader#continueLoading(LoadingInfo)} returns true if any
+ * loader that are behind current playback position can make progress, even if it is not the one
+ * with minimum next load position.
*/
@Test
public void continueLoadingReturnTrueIfLoaderBehindPlaybackPositionCanMakeProgress() {
@@ -225,7 +232,10 @@ public final class CompositeSequenceableLoaderTest {
CompositeSequenceableLoader compositeSequenceableLoader =
new CompositeSequenceableLoader(new SequenceableLoader[] {loader1, loader2});
- assertThat(compositeSequenceableLoader.continueLoading(3000)).isTrue();
+ assertThat(
+ compositeSequenceableLoader.continueLoading(
+ new LoadingInfo.Builder().setPlaybackPositionUs(3000).build()))
+ .isTrue();
}
private static class FakeSequenceableLoader implements SequenceableLoader {
@@ -251,7 +261,7 @@ public final class CompositeSequenceableLoaderTest {
}
@Override
- public boolean continueLoading(long positionUs) {
+ public boolean continueLoading(LoadingInfo loadingInfo) {
numInvocations++;
boolean loaded = nextChunkDurationUs != 0;
// The current chunk has been loaded, advance to next chunk.
diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ConcatenatingMediaSource2Test.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ConcatenatingMediaSource2Test.java
index 85ad9ee398..4635cba6e8 100644
--- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ConcatenatingMediaSource2Test.java
+++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ConcatenatingMediaSource2Test.java
@@ -41,6 +41,7 @@ import androidx.media3.common.Timeline;
import androidx.media3.common.util.Util;
import androidx.media3.datasource.TransferListener;
import androidx.media3.exoplayer.ExoPlayer;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.util.EventLogger;
import androidx.media3.test.utils.FakeMediaSource;
@@ -736,7 +737,7 @@ public final class ConcatenatingMediaSource2Test {
@Override
public void onContinueLoadingRequested(MediaPeriod source) {
- mediaPeriod.continueLoading(/* positionUs= */ 0);
+ mediaPeriod.continueLoading(new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
}
},
/* positionUs= */ 0);
diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/MergingMediaPeriodTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/MergingMediaPeriodTest.java
index b9ef909b08..92bd17b894 100644
--- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/MergingMediaPeriodTest.java
+++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/MergingMediaPeriodTest.java
@@ -26,6 +26,7 @@ import androidx.media3.common.TrackGroup;
import androidx.media3.common.util.NullableType;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.exoplayer.FormatHolder;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
import androidx.media3.exoplayer.drm.DrmSessionManager;
import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId;
@@ -88,7 +89,7 @@ public final class MergingMediaPeriodTest {
streams,
/* streamResetFlags= */ new boolean[] {false, false, false, false},
/* positionUs= */ 0);
- mergingMediaPeriod.continueLoading(/* positionUs= */ 0);
+ mergingMediaPeriod.continueLoading(new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
assertThat(streams[0]).isNull();
assertThat(streams[3]).isNull();
@@ -133,7 +134,7 @@ public final class MergingMediaPeriodTest {
streams,
/* streamResetFlags= */ new boolean[] {false, false},
/* positionUs= */ 0);
- mergingMediaPeriod.continueLoading(/* positionUs= */ 0);
+ mergingMediaPeriod.continueLoading(new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
FormatHolder formatHolder = new FormatHolder();
DecoderInputBuffer inputBuffer =
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
@@ -219,7 +220,7 @@ public final class MergingMediaPeriodTest {
streams,
/* streamResetFlags= */ new boolean[2],
/* positionUs= */ 0);
- mergingMediaPeriod.continueLoading(/* positionUs= */ 0);
+ mergingMediaPeriod.continueLoading(new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
FormatHolder formatHolder = new FormatHolder();
DecoderInputBuffer inputBuffer =
@@ -266,7 +267,8 @@ public final class MergingMediaPeriodTest {
@Override
public void onContinueLoadingRequested(MediaPeriod source) {
- mergingMediaPeriod.continueLoading(/* positionUs= */ 0);
+ mergingMediaPeriod.continueLoading(
+ new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
}
},
/* positionUs= */ 0);
diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ProgressiveMediaPeriodTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ProgressiveMediaPeriodTest.java
index bd3836b4ad..77789ed863 100644
--- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ProgressiveMediaPeriodTest.java
+++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ProgressiveMediaPeriodTest.java
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
import androidx.media3.common.C;
import androidx.media3.datasource.AssetDataSource;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
import androidx.media3.exoplayer.drm.DrmSessionManager;
@@ -87,7 +88,7 @@ public final class ProgressiveMediaPeriodTest {
@Override
public void onContinueLoadingRequested(MediaPeriod source) {
- source.continueLoading(/* positionUs= */ 0);
+ source.continueLoading(new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
}
},
/* positionUs= */ 0);
diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ads/ServerSideAdInsertionMediaSourceTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ads/ServerSideAdInsertionMediaSourceTest.java
index a1cad8a2a9..85b1f006d3 100644
--- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ads/ServerSideAdInsertionMediaSourceTest.java
+++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/ads/ServerSideAdInsertionMediaSourceTest.java
@@ -54,6 +54,7 @@ import androidx.media3.datasource.TransferListener;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.FormatHolder;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.analytics.AnalyticsListener;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
@@ -805,7 +806,8 @@ public final class ServerSideAdInsertionMediaSourceTest {
@Override
public void onContinueLoadingRequested(MediaPeriod source) {
- serverSideAdInsertionMediaPeriod.continueLoading(/* positionUs= */ 0);
+ serverSideAdInsertionMediaPeriod.continueLoading(
+ new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
}
},
/* positionUs= */ 0);
diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java
index 83cf4cd401..6b8dd841f1 100644
--- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java
+++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java
@@ -51,6 +51,7 @@ import androidx.media3.common.VideoSize;
import androidx.media3.common.util.Clock;
import androidx.media3.decoder.CryptoInfo;
import androidx.media3.exoplayer.DecoderCounters;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.Renderer;
import androidx.media3.exoplayer.RendererCapabilities;
import androidx.media3.exoplayer.RendererCapabilities.Capabilities;
@@ -352,7 +353,8 @@ public class MediaCodecVideoRendererTest {
@Override
public void onContinueLoadingRequested(MediaPeriod source) {
- clippingMediaPeriod.continueLoading(/* positionUs= */ 0);
+ clippingMediaPeriod.continueLoading(
+ new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
}
},
/* positionUs= */ 100);
@@ -456,7 +458,8 @@ public class MediaCodecVideoRendererTest {
@Override
public void onContinueLoadingRequested(MediaPeriod source) {
- clippingMediaPeriod.continueLoading(/* positionUs= */ 0);
+ clippingMediaPeriod.continueLoading(
+ new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
}
},
/* positionUs= */ 100);
diff --git a/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/DashMediaPeriod.java b/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/DashMediaPeriod.java
index 5e1485f04c..04ba72a6ad 100644
--- a/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/DashMediaPeriod.java
+++ b/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/DashMediaPeriod.java
@@ -30,6 +30,7 @@ import androidx.media3.common.TrackGroup;
import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.Util;
import androidx.media3.datasource.TransferListener;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.dash.PlayerEmsgHandler.PlayerEmsgCallback;
@@ -316,8 +317,8 @@ import java.util.regex.Pattern;
}
@Override
- public boolean continueLoading(long positionUs) {
- return compositeSequenceableLoader.continueLoading(positionUs);
+ public boolean continueLoading(LoadingInfo loadingInfo) {
+ return compositeSequenceableLoader.continueLoading(loadingInfo);
}
@Override
diff --git a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsMediaPeriod.java b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsMediaPeriod.java
index a8e4a311e1..9174c99924 100644
--- a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsMediaPeriod.java
+++ b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsMediaPeriod.java
@@ -31,6 +31,7 @@ import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.TransferListener;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.drm.DrmSession;
@@ -391,7 +392,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsPlaylistTracker.Pla
}
@Override
- public boolean continueLoading(long positionUs) {
+ public boolean continueLoading(LoadingInfo loadingInfo) {
if (trackGroups == null) {
// Preparation is still going on.
for (HlsSampleStreamWrapper wrapper : sampleStreamWrappers) {
@@ -399,7 +400,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsPlaylistTracker.Pla
}
return false;
} else {
- return compositeSequenceableLoader.continueLoading(positionUs);
+ return compositeSequenceableLoader.continueLoading(loadingInfo);
}
}
diff --git a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsSampleStreamWrapper.java b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsSampleStreamWrapper.java
index 6b024150b6..9c95d0d885 100644
--- a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsSampleStreamWrapper.java
+++ b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsSampleStreamWrapper.java
@@ -41,6 +41,7 @@ import androidx.media3.common.util.Util;
import androidx.media3.datasource.HttpDataSource;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.exoplayer.FormatHolder;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.drm.DrmSession;
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
@@ -109,8 +110,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
void onPrepared();
/**
- * Called to schedule a {@link #continueLoading(long)} call when the playlist referred by the
- * given url changes.
+ * Called to schedule a {@link #continueLoading(LoadingInfo)} call when the playlist referred by
+ * the given url changes.
*/
void onPlaylistRefreshRequired(Uri playlistUrl);
}
@@ -258,7 +259,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
public void continuePreparing() {
if (!prepared) {
- continueLoading(lastSeekPositionUs);
+ continueLoading(new LoadingInfo.Builder().setPlaybackPositionUs(lastSeekPositionUs).build());
}
}
@@ -737,7 +738,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
}
@Override
- public boolean continueLoading(long positionUs) {
+ public boolean continueLoading(LoadingInfo loadingInfo) {
if (loadingFinished || loader.isLoading() || loader.hasFatalError()) {
return false;
}
@@ -760,7 +761,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
}
nextChunkHolder.clear();
chunkSource.getNextChunk(
- positionUs,
+ loadingInfo.playbackPositionUs,
loadPositionUs,
chunkQueue,
/* allowEndOfStream= */ prepared || !chunkQueue.isEmpty(),
@@ -862,7 +863,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
loadable.startTimeUs,
loadable.endTimeUs);
if (!prepared) {
- continueLoading(lastSeekPositionUs);
+ continueLoading(new LoadingInfo.Builder().setPlaybackPositionUs(lastSeekPositionUs).build());
} else {
callback.onContinueLoadingRequested(this);
}
@@ -991,7 +992,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
if (exclusionSucceeded) {
if (!prepared) {
- continueLoading(lastSeekPositionUs);
+ continueLoading(
+ new LoadingInfo.Builder().setPlaybackPositionUs(lastSeekPositionUs).build());
} else {
callback.onContinueLoadingRequested(this);
}
diff --git a/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspMediaPeriod.java b/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspMediaPeriod.java
index 96ea2933e5..a8c8e6fe40 100644
--- a/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspMediaPeriod.java
+++ b/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/RtspMediaPeriod.java
@@ -34,6 +34,7 @@ import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.exoplayer.FormatHolder;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.rtsp.RtspClient.PlaybackEventListener;
import androidx.media3.exoplayer.rtsp.RtspClient.SessionInfoListener;
@@ -373,7 +374,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
@Override
- public boolean continueLoading(long positionUs) {
+ public boolean continueLoading(LoadingInfo loadingInfo) {
return isLoading();
}
diff --git a/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/RtspMediaPeriodTest.java b/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/RtspMediaPeriodTest.java
index caff5bb3f0..3f5613d78c 100644
--- a/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/RtspMediaPeriodTest.java
+++ b/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/RtspMediaPeriodTest.java
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
import androidx.media3.common.C;
import androidx.media3.common.util.Util;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.source.MediaPeriod;
import androidx.media3.exoplayer.upstream.DefaultAllocator;
import androidx.media3.test.utils.robolectric.RobolectricUtil;
@@ -97,7 +98,7 @@ public final class RtspMediaPeriodTest {
@Override
public void onContinueLoadingRequested(MediaPeriod source) {
- source.continueLoading(/* positionUs= */ 0);
+ source.continueLoading(new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
}
},
/* positionUs= */ 0);
@@ -182,7 +183,7 @@ public final class RtspMediaPeriodTest {
@Override
public void onContinueLoadingRequested(MediaPeriod source) {
- source.continueLoading(/* positionUs= */ 0);
+ source.continueLoading(new LoadingInfo.Builder().setPlaybackPositionUs(0).build());
}
},
/* positionUs= */ 0);
diff --git a/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/SsMediaPeriod.java b/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/SsMediaPeriod.java
index 114c2aaf75..267ce1a2ab 100644
--- a/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/SsMediaPeriod.java
+++ b/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/SsMediaPeriod.java
@@ -22,6 +22,7 @@ import androidx.media3.common.StreamKey;
import androidx.media3.common.TrackGroup;
import androidx.media3.common.util.NullableType;
import androidx.media3.datasource.TransferListener;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
import androidx.media3.exoplayer.drm.DrmSessionManager;
@@ -185,8 +186,8 @@ import java.util.List;
}
@Override
- public boolean continueLoading(long positionUs) {
- return compositeSequenceableLoader.continueLoading(positionUs);
+ public boolean continueLoading(LoadingInfo loadingInfo) {
+ return compositeSequenceableLoader.continueLoading(loadingInfo);
}
@Override
diff --git a/libraries/test_utils/src/main/java/androidx/media3/test/utils/FakeAdaptiveMediaPeriod.java b/libraries/test_utils/src/main/java/androidx/media3/test/utils/FakeAdaptiveMediaPeriod.java
index c7f3c48134..804234c446 100644
--- a/libraries/test_utils/src/main/java/androidx/media3/test/utils/FakeAdaptiveMediaPeriod.java
+++ b/libraries/test_utils/src/main/java/androidx/media3/test/utils/FakeAdaptiveMediaPeriod.java
@@ -29,6 +29,7 @@ import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.datasource.DataSpec;
import androidx.media3.datasource.TransferListener;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
import androidx.media3.exoplayer.drm.DrmSessionManager;
@@ -236,8 +237,8 @@ public class FakeAdaptiveMediaPeriod
}
@Override
- public boolean continueLoading(long positionUs) {
- sequenceableLoader.continueLoading(positionUs);
+ public boolean continueLoading(LoadingInfo loadingInfo) {
+ sequenceableLoader.continueLoading(loadingInfo);
return true;
}
diff --git a/libraries/test_utils/src/main/java/androidx/media3/test/utils/FakeMediaPeriod.java b/libraries/test_utils/src/main/java/androidx/media3/test/utils/FakeMediaPeriod.java
index 0e8d91b86d..79e64fda5b 100644
--- a/libraries/test_utils/src/main/java/androidx/media3/test/utils/FakeMediaPeriod.java
+++ b/libraries/test_utils/src/main/java/androidx/media3/test/utils/FakeMediaPeriod.java
@@ -32,6 +32,7 @@ import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.datasource.DataSpec;
+import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
import androidx.media3.exoplayer.drm.DrmSessionManager;
@@ -361,9 +362,9 @@ public class FakeMediaPeriod implements MediaPeriod {
}
@Override
- public boolean continueLoading(long positionUs) {
+ public boolean continueLoading(LoadingInfo loadingInfo) {
for (FakeSampleStream sampleStream : sampleStreams) {
- sampleStream.writeData(positionUs);
+ sampleStream.writeData(loadingInfo.playbackPositionUs);
}
return true;
}