From 481ea4a274173d3aeb4fecc23c94365458b9eb67 Mon Sep 17 00:00:00 2001 From: rohks Date: Wed, 9 Aug 2023 11:41:59 +0000 Subject: [PATCH] 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 --- RELEASENOTES.md | 6 + .../exoplayer/ExoPlayerImplInternal.java | 35 ++++- .../media3/exoplayer/LoadingInfo.java | 123 ++++++++++++++++++ .../media3/exoplayer/MediaPeriodHolder.java | 14 +- .../media3/exoplayer/MetadataRetriever.java | 3 +- .../exoplayer/offline/DownloadHelper.java | 3 +- .../exoplayer/source/ClippingMediaPeriod.java | 5 +- .../source/CompositeSequenceableLoader.java | 7 +- .../source/FilteringMediaSource.java | 5 +- .../exoplayer/source/MaskingMediaPeriod.java | 5 +- .../media3/exoplayer/source/MediaPeriod.java | 7 +- .../exoplayer/source/MergingMediaPeriod.java | 15 ++- .../source/ProgressiveMediaPeriod.java | 3 +- .../exoplayer/source/SequenceableLoader.java | 11 +- .../exoplayer/source/SilenceMediaSource.java | 3 +- .../source/SingleSampleMediaPeriod.java | 3 +- .../ads/ServerSideAdInsertionMediaSource.java | 12 +- .../source/chunk/ChunkSampleStream.java | 6 +- .../media3/exoplayer/ExoPlayerTest.java | 6 +- .../source/ClippingMediaPeriodTest.java | 4 +- .../CompositeSequenceableLoaderTest.java | 48 ++++--- .../source/ConcatenatingMediaSource2Test.java | 3 +- .../source/MergingMediaPeriodTest.java | 10 +- .../source/ProgressiveMediaPeriodTest.java | 3 +- .../ServerSideAdInsertionMediaSourceTest.java | 4 +- .../video/MediaCodecVideoRendererTest.java | 7 +- .../exoplayer/dash/DashMediaPeriod.java | 5 +- .../media3/exoplayer/hls/HlsMediaPeriod.java | 5 +- .../exoplayer/hls/HlsSampleStreamWrapper.java | 16 ++- .../exoplayer/rtsp/RtspMediaPeriod.java | 3 +- .../exoplayer/rtsp/RtspMediaPeriodTest.java | 5 +- .../smoothstreaming/SsMediaPeriod.java | 5 +- .../test/utils/FakeAdaptiveMediaPeriod.java | 5 +- .../media3/test/utils/FakeMediaPeriod.java | 5 +- 34 files changed, 304 insertions(+), 96 deletions(-) create mode 100644 libraries/exoplayer/src/main/java/androidx/media3/exoplayer/LoadingInfo.java 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; }