Enhance continueLoading() API to allow passing more information

Modifies the `SequenceableLoader.continueLoading(long)` method in the `SequenceableLoader` interface to `SequenceableLoader.continueLoading(LoadingInfo)`.

`LoadingInfo` contains additional parameters, including `playbackSpeed` and `lastRebufferRealtimeMs` in addition to the existing `playbackPositionUs`. The additional parameters will allow us to pass these information to Common Media Client Data (CMCD) logging.

By using the `LoadingInfo` object, we ensure future flexibility to add more fields without causing any breaking changes to the API.

PiperOrigin-RevId: 555123961
This commit is contained in:
rohks 2023-08-09 11:41:59 +00:00 committed by Tianyi Feng
parent 2da3cc71e5
commit 481ea4a274
34 changed files with 304 additions and 96 deletions

View File

@ -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

View File

@ -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.<br>
* If set to {@code true}, the method resets the {@link #lastRebufferRealtimeMs} to {@link
* C#TIME_UNSET}.<br>
* 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.
*

View File

@ -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.
*
* <p>The time base used is the same as that measured by {@link SystemClock#elapsedRealtime}.
*
* <p><b>Note:</b> 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);
}
}

View File

@ -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());
}
/**

View File

@ -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) {

View File

@ -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:

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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<T extends SequenceableLoader> {
/**
* 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();

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<LoadEventInfo, MediaLoadData> 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

View File

@ -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<T extends ChunkSource>
// 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<T extends ChunkSource>
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();

View File

@ -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);

View File

@ -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);

View File

@ -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.

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}