From 5485133e5c7965f98d71da3cb92033b35f596c61 Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 11 Mar 2020 12:23:45 +0000 Subject: [PATCH] Rollback of https://github.com/google/ExoPlayer/commit/949bbcfb2e98c5cb76ebb35d68fc9f0da4706f16 *** Original commit *** Add masking for playWhenReady. Masking is needed as soon as updates to a value can happen both in EPI and EPII. PlayWhenReady is currently not masked because all updates happen in EPI only. As soon as we allow pausing at certain times (e.g. end of a stream), playWhenReady changes may be triggered by EPII as well and that's why we need masking. To know when the value actually changed, we also need to update the internal state to include whether playback is supppressed. *** PiperOrigin-RevId: 300303307 --- .../android/exoplayer2/ExoPlayerImpl.java | 164 ++++++++---------- .../exoplayer2/ExoPlayerImplInternal.java | 112 +++++------- .../android/exoplayer2/PlaybackInfo.java | 52 ------ .../android/exoplayer2/ExoPlayerTest.java | 2 - .../exoplayer2/MediaPeriodQueueTest.java | 2 - .../analytics/AnalyticsCollectorTest.java | 31 +--- 6 files changed, 117 insertions(+), 246 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 57da40fc68..e807f3f169 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -70,13 +70,12 @@ import java.util.concurrent.TimeoutException; private final List mediaSourceHolders; private final boolean useLazyPreparation; + private boolean playWhenReady; + @PlaybackSuppressionReason private int playbackSuppressionReason; @RepeatMode private int repeatMode; private boolean shuffleModeEnabled; private int pendingOperationAcks; private boolean hasPendingSeek; - private boolean hasPendingDiscontinuity; - @DiscontinuityReason private int pendingDiscontinuityReason; - @PlayWhenReadyChangeReason private int pendingPlayWhenReadyChangeReason; private boolean foregroundMode; private int pendingSetPlaybackParametersAcks; private PlaybackParameters playbackParameters; @@ -122,7 +121,9 @@ import java.util.concurrent.TimeoutException; this.renderers = Assertions.checkNotNull(renderers); this.trackSelector = Assertions.checkNotNull(trackSelector); this.useLazyPreparation = useLazyPreparation; + playWhenReady = false; repeatMode = Player.REPEAT_MODE_OFF; + shuffleModeEnabled = false; listeners = new CopyOnWriteArrayList<>(); mediaSourceHolders = new ArrayList<>(); shuffleOrder = new ShuffleOrder.DefaultShuffleOrder(/* length= */ 0); @@ -134,6 +135,7 @@ import java.util.concurrent.TimeoutException; period = new Timeline.Period(); playbackParameters = PlaybackParameters.DEFAULT; seekParameters = SeekParameters.DEFAULT; + playbackSuppressionReason = PLAYBACK_SUPPRESSION_REASON_NONE; maskingWindowIndex = C.INDEX_UNSET; eventHandler = new Handler(looper) { @@ -154,6 +156,7 @@ import java.util.concurrent.TimeoutException; emptyTrackSelectorResult, loadControl, bandwidthMeter, + playWhenReady, repeatMode, shuffleModeEnabled, analyticsCollector, @@ -234,7 +237,7 @@ import java.util.concurrent.TimeoutException; @Override @PlaybackSuppressionReason public int getPlaybackSuppressionReason() { - return playbackInfo.playbackSuppressionReason; + return playbackSuppressionReason; } @Deprecated @@ -280,7 +283,6 @@ import java.util.concurrent.TimeoutException; /* positionDiscontinuity= */ false, /* ignored */ DISCONTINUITY_REASON_INTERNAL, /* ignored */ TIMELINE_CHANGE_REASON_SOURCE_UPDATE, - /* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST, /* seekProcessed= */ false); } @@ -441,36 +443,40 @@ import java.util.concurrent.TimeoutException; @PlaybackSuppressionReason int playbackSuppressionReason, @PlayWhenReadyChangeReason int playWhenReadyChangeReason) { boolean oldIsPlaying = isPlaying(); - boolean playWhenReadyChanged = playbackInfo.playWhenReady != playWhenReady; - boolean suppressionReasonChanged = - playbackInfo.playbackSuppressionReason != playbackSuppressionReason; - if (!playWhenReadyChanged && !suppressionReasonChanged) { - return; + boolean oldInternalPlayWhenReady = + this.playWhenReady && this.playbackSuppressionReason == PLAYBACK_SUPPRESSION_REASON_NONE; + boolean internalPlayWhenReady = + playWhenReady && playbackSuppressionReason == PLAYBACK_SUPPRESSION_REASON_NONE; + if (oldInternalPlayWhenReady != internalPlayWhenReady) { + internalPlayer.setPlayWhenReady(internalPlayWhenReady); } - pendingOperationAcks++; - playbackInfo = playbackInfo.copyWithPlayWhenReady(playWhenReady, playbackSuppressionReason); - internalPlayer.setPlayWhenReady(playWhenReady, playbackSuppressionReason); + boolean playWhenReadyChanged = this.playWhenReady != playWhenReady; + boolean suppressionReasonChanged = this.playbackSuppressionReason != playbackSuppressionReason; + this.playWhenReady = playWhenReady; + this.playbackSuppressionReason = playbackSuppressionReason; boolean isPlaying = isPlaying(); boolean isPlayingChanged = oldIsPlaying != isPlaying; - int playbackState = playbackInfo.playbackState; - notifyListeners( - listener -> { - if (playWhenReadyChanged) { - listener.onPlayerStateChanged(playWhenReady, playbackState); - listener.onPlayWhenReadyChanged(playWhenReady, playWhenReadyChangeReason); - } - if (suppressionReasonChanged) { - listener.onPlaybackSuppressionReasonChanged(playbackSuppressionReason); - } - if (isPlayingChanged) { - listener.onIsPlayingChanged(isPlaying); - } - }); + if (playWhenReadyChanged || suppressionReasonChanged || isPlayingChanged) { + int playbackState = playbackInfo.playbackState; + notifyListeners( + listener -> { + if (playWhenReadyChanged) { + listener.onPlayerStateChanged(playWhenReady, playbackState); + listener.onPlayWhenReadyChanged(playWhenReady, playWhenReadyChangeReason); + } + if (suppressionReasonChanged) { + listener.onPlaybackSuppressionReasonChanged(playbackSuppressionReason); + } + if (isPlayingChanged) { + listener.onIsPlayingChanged(isPlaying); + } + }); + } } @Override public boolean getPlayWhenReady() { - return playbackInfo.playWhenReady; + return playWhenReady; } @Override @@ -595,7 +601,6 @@ import java.util.concurrent.TimeoutException; /* positionDiscontinuity= */ false, /* ignored */ DISCONTINUITY_REASON_INTERNAL, TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED, - /* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST, /* seekProcessed= */ false); } @@ -758,9 +763,14 @@ import java.util.concurrent.TimeoutException; // Not private so it can be called from an inner class without going through a thunk method. /* package */ void handleEvent(Message msg) { + switch (msg.what) { case ExoPlayerImplInternal.MSG_PLAYBACK_INFO_CHANGED: - handlePlaybackInfo((ExoPlayerImplInternal.PlaybackInfoUpdate) msg.obj); + handlePlaybackInfo( + /* playbackInfo= */ (PlaybackInfo) msg.obj, + /* operationAcks= */ msg.arg1, + /* positionDiscontinuity= */ msg.arg2 != C.INDEX_UNSET, + /* positionDiscontinuityReason= */ msg.arg2); break; case ExoPlayerImplInternal.MSG_PLAYBACK_PARAMETERS_CHANGED: handlePlaybackParameters((PlaybackParameters) msg.obj, /* operationAck= */ msg.arg1 != 0); @@ -792,31 +802,24 @@ import java.util.concurrent.TimeoutException; } } - private void handlePlaybackInfo(ExoPlayerImplInternal.PlaybackInfoUpdate playbackInfoUpdate) { - pendingOperationAcks -= playbackInfoUpdate.operationAcks; - if (playbackInfoUpdate.positionDiscontinuity) { - hasPendingDiscontinuity = true; - pendingDiscontinuityReason = playbackInfoUpdate.discontinuityReason; - } - if (playbackInfoUpdate.hasPlayWhenReadyChangeReason) { - pendingPlayWhenReadyChangeReason = playbackInfoUpdate.playWhenReadyChangeReason; - } + private void handlePlaybackInfo( + PlaybackInfo playbackInfo, + int operationAcks, + boolean positionDiscontinuity, + @DiscontinuityReason int positionDiscontinuityReason) { + pendingOperationAcks -= operationAcks; if (pendingOperationAcks == 0) { - if (!this.playbackInfo.timeline.isEmpty() - && playbackInfoUpdate.playbackInfo.timeline.isEmpty()) { + if (!this.playbackInfo.timeline.isEmpty() && playbackInfo.timeline.isEmpty()) { // Update the masking variables, which are used when the timeline becomes empty. resetMaskingPosition(); } boolean seekProcessed = hasPendingSeek; - boolean positionDiscontinuity = hasPendingDiscontinuity; hasPendingSeek = false; - hasPendingDiscontinuity = false; updatePlaybackInfo( - playbackInfoUpdate.playbackInfo, + playbackInfo, positionDiscontinuity, - pendingDiscontinuityReason, + positionDiscontinuityReason, TIMELINE_CHANGE_REASON_SOURCE_UPDATE, - pendingPlayWhenReadyChangeReason, seekProcessed); } } @@ -853,8 +856,6 @@ import java.util.concurrent.TimeoutException; clearPlaylist ? TrackGroupArray.EMPTY : playbackInfo.trackGroups, clearPlaylist ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult, mediaPeriodId, - playbackInfo.playWhenReady, - playbackInfo.playbackSuppressionReason, positionUs, /* totalBufferedDurationUs= */ 0, positionUs); @@ -865,11 +866,12 @@ import java.util.concurrent.TimeoutException; boolean positionDiscontinuity, @DiscontinuityReason int positionDiscontinuityReason, @TimelineChangeReason int timelineChangeReason, - @PlayWhenReadyChangeReason int playWhenReadyChangeReason, boolean seekProcessed) { + boolean previousIsPlaying = isPlaying(); // Assign playback info immediately such that all getters return the right values. PlaybackInfo previousPlaybackInfo = this.playbackInfo; this.playbackInfo = playbackInfo; + boolean isPlaying = isPlaying(); notifyListeners( new PlaybackInfoUpdate( playbackInfo, @@ -879,8 +881,9 @@ import java.util.concurrent.TimeoutException; positionDiscontinuity, positionDiscontinuityReason, timelineChangeReason, - playWhenReadyChangeReason, - seekProcessed)); + seekProcessed, + playWhenReady, + /* isPlayingChanged= */ previousIsPlaying != isPlaying)); } @SuppressWarnings("deprecation") @@ -1133,18 +1136,16 @@ import java.util.concurrent.TimeoutException; private final CopyOnWriteArrayList listenerSnapshot; private final TrackSelector trackSelector; private final boolean positionDiscontinuity; - @DiscontinuityReason private final int positionDiscontinuityReason; - @TimelineChangeReason private final int timelineChangeReason; - @PlayWhenReadyChangeReason private final int playWhenReadyChangeReason; + private final @Player.DiscontinuityReason int positionDiscontinuityReason; + private final int timelineChangeReason; private final boolean seekProcessed; private final boolean playbackStateChanged; private final boolean playbackErrorChanged; private final boolean timelineChanged; private final boolean isLoadingChanged; private final boolean trackSelectorResultChanged; + private final boolean playWhenReady; private final boolean isPlayingChanged; - private final boolean playWhenReadyChanged; - private final boolean playbackSuppressionReasonChanged; public PlaybackInfoUpdate( PlaybackInfo playbackInfo, @@ -1154,16 +1155,18 @@ import java.util.concurrent.TimeoutException; boolean positionDiscontinuity, @DiscontinuityReason int positionDiscontinuityReason, @TimelineChangeReason int timelineChangeReason, - @PlayWhenReadyChangeReason int playWhenReadyChangeReason, - boolean seekProcessed) { + boolean seekProcessed, + boolean playWhenReady, + boolean isPlayingChanged) { this.playbackInfo = playbackInfo; this.listenerSnapshot = new CopyOnWriteArrayList<>(listeners); this.trackSelector = trackSelector; this.positionDiscontinuity = positionDiscontinuity; this.positionDiscontinuityReason = positionDiscontinuityReason; this.timelineChangeReason = timelineChangeReason; - this.playWhenReadyChangeReason = playWhenReadyChangeReason; this.seekProcessed = seekProcessed; + this.playWhenReady = playWhenReady; + this.isPlayingChanged = isPlayingChanged; playbackStateChanged = previousPlaybackInfo.playbackState != playbackInfo.playbackState; playbackErrorChanged = previousPlaybackInfo.playbackError != playbackInfo.playbackError @@ -1172,10 +1175,6 @@ import java.util.concurrent.TimeoutException; timelineChanged = !previousPlaybackInfo.timeline.equals(playbackInfo.timeline); trackSelectorResultChanged = previousPlaybackInfo.trackSelectorResult != playbackInfo.trackSelectorResult; - playWhenReadyChanged = previousPlaybackInfo.playWhenReady != playbackInfo.playWhenReady; - playbackSuppressionReasonChanged = - previousPlaybackInfo.playbackSuppressionReason != playbackInfo.playbackSuppressionReason; - isPlayingChanged = isPlaying(previousPlaybackInfo) != isPlaying(playbackInfo); } @SuppressWarnings("deprecation") @@ -1203,49 +1202,30 @@ import java.util.concurrent.TimeoutException; playbackInfo.trackGroups, playbackInfo.trackSelectorResult.selections)); } if (isLoadingChanged) { - invokeAll( - listenerSnapshot, listener -> listener.onIsLoadingChanged(playbackInfo.isLoading)); - } - if (playbackStateChanged || playWhenReadyChanged) { invokeAll( listenerSnapshot, - listener -> - listener.onPlayerStateChanged( - playbackInfo.playWhenReady, playbackInfo.playbackState)); + listener -> { + listener.onIsLoadingChanged(playbackInfo.isLoading); + }); } if (playbackStateChanged) { invokeAll( listenerSnapshot, - listener -> listener.onPlaybackStateChanged(playbackInfo.playbackState)); - } - if (playWhenReadyChanged) { - invokeAll( - listenerSnapshot, - listener -> - listener.onPlayWhenReadyChanged( - playbackInfo.playWhenReady, playWhenReadyChangeReason)); - } - if (playbackSuppressionReasonChanged) { - invokeAll( - listenerSnapshot, - listener -> - listener.onPlaybackSuppressionReasonChanged( - playbackInfo.playbackSuppressionReason)); + listener -> { + listener.onPlayerStateChanged(playWhenReady, playbackInfo.playbackState); + listener.onPlaybackStateChanged(playbackInfo.playbackState); + }); } if (isPlayingChanged) { invokeAll( - listenerSnapshot, listener -> listener.onIsPlayingChanged(isPlaying(playbackInfo))); + listenerSnapshot, + listener -> + listener.onIsPlayingChanged(playbackInfo.playbackState == Player.STATE_READY)); } if (seekProcessed) { invokeAll(listenerSnapshot, EventListener::onSeekProcessed); } } - - private static boolean isPlaying(PlaybackInfo playbackInfo) { - return playbackInfo.playbackState == Player.STATE_READY - && playbackInfo.playWhenReady - && playbackInfo.playbackSuppressionReason == PLAYBACK_SUPPRESSION_REASON_NONE; - } } private static void invokeAll( diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index a81deb1ba5..e93d336ab9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -26,8 +26,6 @@ import androidx.annotation.CheckResult; import androidx.annotation.Nullable; import com.google.android.exoplayer2.DefaultMediaClock.PlaybackParameterListener; import com.google.android.exoplayer2.Player.DiscontinuityReason; -import com.google.android.exoplayer2.Player.PlayWhenReadyChangeReason; -import com.google.android.exoplayer2.Player.PlaybackSuppressionReason; import com.google.android.exoplayer2.Player.RepeatMode; import com.google.android.exoplayer2.analytics.AnalyticsCollector; import com.google.android.exoplayer2.source.MediaPeriod; @@ -109,6 +107,7 @@ import java.util.concurrent.atomic.AtomicBoolean; private final long backBufferDurationUs; private final boolean retainBackBufferFromKeyframe; private final DefaultMediaClock mediaClock; + private final PlaybackInfoUpdate playbackInfoUpdate; private final ArrayList pendingMessages; private final Clock clock; private final MediaPeriodQueue queue; @@ -118,9 +117,9 @@ import java.util.concurrent.atomic.AtomicBoolean; private SeekParameters seekParameters; private PlaybackInfo playbackInfo; - private PlaybackInfoUpdate playbackInfoUpdate; private Renderer[] enabledRenderers; private boolean released; + private boolean playWhenReady; private boolean pauseAtEndOfWindow; private boolean pendingPauseAtEndOfPeriod; private boolean rebuffering; @@ -142,6 +141,7 @@ import java.util.concurrent.atomic.AtomicBoolean; TrackSelectorResult emptyTrackSelectorResult, LoadControl loadControl, BandwidthMeter bandwidthMeter, + boolean playWhenReady, @Player.RepeatMode int repeatMode, boolean shuffleModeEnabled, @Nullable AnalyticsCollector analyticsCollector, @@ -152,6 +152,7 @@ import java.util.concurrent.atomic.AtomicBoolean; this.emptyTrackSelectorResult = emptyTrackSelectorResult; this.loadControl = loadControl; this.bandwidthMeter = bandwidthMeter; + this.playWhenReady = playWhenReady; this.repeatMode = repeatMode; this.shuffleModeEnabled = shuffleModeEnabled; this.eventHandler = eventHandler; @@ -163,7 +164,7 @@ import java.util.concurrent.atomic.AtomicBoolean; seekParameters = SeekParameters.DEFAULT; playbackInfo = PlaybackInfo.createDummy(emptyTrackSelectorResult); - playbackInfoUpdate = new PlaybackInfoUpdate(playbackInfo); + playbackInfoUpdate = new PlaybackInfoUpdate(); rendererCapabilities = new RendererCapabilities[renderers.length]; for (int i = 0; i < renderers.length; i++) { renderers[i].setIndex(i); @@ -197,11 +198,8 @@ import java.util.concurrent.atomic.AtomicBoolean; handler.obtainMessage(MSG_PREPARE).sendToTarget(); } - public void setPlayWhenReady( - boolean playWhenReady, @PlaybackSuppressionReason int playbackSuppressionReason) { - handler - .obtainMessage(MSG_SET_PLAY_WHEN_READY, playWhenReady ? 1 : 0, playbackSuppressionReason) - .sendToTarget(); + public void setPlayWhenReady(boolean playWhenReady) { + handler.obtainMessage(MSG_SET_PLAY_WHEN_READY, playWhenReady ? 1 : 0, 0).sendToTarget(); } public void setPauseAtEndOfWindow(boolean pauseAtEndOfWindow) { @@ -383,11 +381,7 @@ import java.util.concurrent.atomic.AtomicBoolean; prepareInternal(); break; case MSG_SET_PLAY_WHEN_READY: - setPlayWhenReadyInternal( - /* playWhenReady= */ msg.arg1 != 0, - /* playbackSuppressionReason= */ msg.arg2, - /* operationAck= */ true, - Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST); + setPlayWhenReadyInternal(msg.arg1 != 0); break; case MSG_SET_REPEAT_MODE: setRepeatModeInternal(msg.arg1); @@ -577,10 +571,17 @@ import java.util.concurrent.atomic.AtomicBoolean; } private void maybeNotifyPlaybackInfoChanged() { - playbackInfoUpdate.setPlaybackInfo(playbackInfo); - if (playbackInfoUpdate.hasPendingChange) { - eventHandler.obtainMessage(MSG_PLAYBACK_INFO_CHANGED, playbackInfoUpdate).sendToTarget(); - playbackInfoUpdate = new PlaybackInfoUpdate(playbackInfo); + if (playbackInfoUpdate.hasPendingUpdate(playbackInfo)) { + eventHandler + .obtainMessage( + MSG_PLAYBACK_INFO_CHANGED, + playbackInfoUpdate.operationAcks, + playbackInfoUpdate.positionDiscontinuity + ? playbackInfoUpdate.discontinuityReason + : C.INDEX_UNSET, + playbackInfo) + .sendToTarget(); + playbackInfoUpdate.reset(playbackInfo); } } @@ -655,17 +656,10 @@ import java.util.concurrent.atomic.AtomicBoolean; handlePlaylistInfoRefreshed(timeline); } - private void setPlayWhenReadyInternal( - boolean playWhenReady, - @PlaybackSuppressionReason int playbackSuppressionReason, - boolean operationAck, - @Player.PlayWhenReadyChangeReason int reason) - throws ExoPlaybackException { - playbackInfoUpdate.incrementPendingOperationAcks(operationAck ? 1 : 0); - playbackInfoUpdate.setPlayWhenReadyChangeReason(reason); - playbackInfo = playbackInfo.copyWithPlayWhenReady(playWhenReady, playbackSuppressionReason); + private void setPlayWhenReadyInternal(boolean playWhenReady) throws ExoPlaybackException { rebuffering = false; - if (!shouldPlayWhenReady()) { + this.playWhenReady = playWhenReady; + if (!playWhenReady) { stopRenderers(); updatePlaybackPositions(); } else { @@ -846,12 +840,7 @@ import java.util.concurrent.atomic.AtomicBoolean; || playingPeriodDurationUs <= playbackInfo.positionUs); if (finishedRendering && pendingPauseAtEndOfPeriod) { pendingPauseAtEndOfPeriod = false; - // TODO: Add new change reason for timed pause requests. - setPlayWhenReadyInternal( - /* playWhenReady= */ false, - playbackInfo.playbackSuppressionReason, - /* operationAck= */ false, - Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST); + setPlayWhenReadyInternal(false); } if (finishedRendering && playingPeriodHolder.info.isFinal) { setState(Player.STATE_ENDED); @@ -859,12 +848,12 @@ import java.util.concurrent.atomic.AtomicBoolean; } else if (playbackInfo.playbackState == Player.STATE_BUFFERING && shouldTransitionToReadyState(renderersAllowPlayback)) { setState(Player.STATE_READY); - if (shouldPlayWhenReady()) { + if (playWhenReady) { startRenderers(); } } else if (playbackInfo.playbackState == Player.STATE_READY && !(enabledRenderers.length == 0 ? isTimelineReady() : renderersAllowPlayback)) { - rebuffering = shouldPlayWhenReady(); + rebuffering = playWhenReady; setState(Player.STATE_BUFFERING); stopRenderers(); } @@ -875,7 +864,7 @@ import java.util.concurrent.atomic.AtomicBoolean; } } - if ((shouldPlayWhenReady() && playbackInfo.playbackState == Player.STATE_READY) + if ((playWhenReady && playbackInfo.playbackState == Player.STATE_READY) || playbackInfo.playbackState == Player.STATE_BUFFERING) { scheduleNextWork(operationStartTimeMs, ACTIVE_INTERVAL_MS); } else if (enabledRenderers.length != 0 && playbackInfo.playbackState != Player.STATE_ENDED) { @@ -917,7 +906,7 @@ import java.util.concurrent.atomic.AtomicBoolean; periodId = firstPeriodAndPosition.first; periodPositionUs = firstPeriodAndPosition.second; requestedContentPosition = C.TIME_UNSET; - seekPositionAdjusted = !playbackInfo.timeline.isEmpty(); + seekPositionAdjusted = true; } else { // Update the resolved seek position to take ads into account. Object periodUid = resolvedSeekPosition.first; @@ -1220,8 +1209,6 @@ import java.util.concurrent.atomic.AtomicBoolean; resetTrackInfo ? TrackGroupArray.EMPTY : playbackInfo.trackGroups, resetTrackInfo ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult, mediaPeriodId, - playbackInfo.playWhenReady, - playbackInfo.playbackSuppressionReason, startPositionUs, /* totalBufferedDurationUs= */ 0, startPositionUs); @@ -1819,7 +1806,7 @@ import java.util.concurrent.atomic.AtomicBoolean; } private boolean shouldAdvancePlayingPeriod() { - if (!shouldPlayWhenReady()) { + if (!playWhenReady) { return false; } if (pendingPauseAtEndOfPeriod) { @@ -2061,7 +2048,7 @@ import java.util.concurrent.atomic.AtomicBoolean; TrackSelection newSelection = trackSelectorResult.selections.get(rendererIndex); Format[] formats = getFormats(newSelection); // The renderer needs enabling with its new track selection. - boolean playing = shouldPlayWhenReady() && playbackInfo.playbackState == Player.STATE_READY; + boolean playing = playWhenReady && playbackInfo.playbackState == Player.STATE_READY; // Consider as joining only if the renderer was previously disabled. boolean joining = !wasRendererEnabled && playing; // Enable the renderer. @@ -2134,11 +2121,6 @@ import java.util.concurrent.atomic.AtomicBoolean; .sendToTarget(); } - private boolean shouldPlayWhenReady() { - return playbackInfo.playWhenReady - && playbackInfo.playbackSuppressionReason == Player.PLAYBACK_SUPPRESSION_REASON_NONE; - } - private static PositionUpdateForPlaylistChange resolvePositionForPlaylistChange( Timeline timeline, PlaybackInfo playbackInfo, @@ -2624,31 +2606,27 @@ import java.util.concurrent.atomic.AtomicBoolean; } } - /* package */ static final class PlaybackInfoUpdate { + private static final class PlaybackInfoUpdate { - private boolean hasPendingChange; + private PlaybackInfo lastPlaybackInfo; + private int operationAcks; + private boolean positionDiscontinuity; + @DiscontinuityReason private int discontinuityReason; - public PlaybackInfo playbackInfo; - public int operationAcks; - public boolean positionDiscontinuity; - @DiscontinuityReason public int discontinuityReason; - public boolean hasPlayWhenReadyChangeReason; - @PlayWhenReadyChangeReason public int playWhenReadyChangeReason; + public boolean hasPendingUpdate(PlaybackInfo playbackInfo) { + return playbackInfo != lastPlaybackInfo || operationAcks > 0 || positionDiscontinuity; + } - public PlaybackInfoUpdate(PlaybackInfo playbackInfo) { - this.playbackInfo = playbackInfo; + public void reset(PlaybackInfo playbackInfo) { + lastPlaybackInfo = playbackInfo; + operationAcks = 0; + positionDiscontinuity = false; } public void incrementPendingOperationAcks(int operationAcks) { - hasPendingChange |= operationAcks > 0; this.operationAcks += operationAcks; } - public void setPlaybackInfo(PlaybackInfo playbackInfo) { - hasPendingChange |= this.playbackInfo != playbackInfo; - this.playbackInfo = playbackInfo; - } - public void setPositionDiscontinuity(@DiscontinuityReason int discontinuityReason) { if (positionDiscontinuity && this.discontinuityReason != Player.DISCONTINUITY_REASON_INTERNAL) { @@ -2657,16 +2635,8 @@ import java.util.concurrent.atomic.AtomicBoolean; Assertions.checkArgument(discontinuityReason == Player.DISCONTINUITY_REASON_INTERNAL); return; } - hasPendingChange = true; positionDiscontinuity = true; this.discontinuityReason = discontinuityReason; } - - public void setPlayWhenReadyChangeReason( - @PlayWhenReadyChangeReason int playWhenReadyChangeReason) { - hasPendingChange = true; - this.hasPlayWhenReadyChangeReason = true; - this.playWhenReadyChangeReason = playWhenReadyChangeReason; - } } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java index f183af0d8c..d545ce4905 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java @@ -17,7 +17,6 @@ package com.google.android.exoplayer2; import androidx.annotation.CheckResult; import androidx.annotation.Nullable; -import com.google.android.exoplayer2.Player.PlaybackSuppressionReason; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.TrackSelectorResult; @@ -59,10 +58,6 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; public final TrackSelectorResult trackSelectorResult; /** The {@link MediaPeriodId} of the currently loading media period in the {@link #timeline}. */ public final MediaPeriodId loadingMediaPeriodId; - /** Whether playback should proceed when {@link #playbackState} == {@link Player#STATE_READY}. */ - public final boolean playWhenReady; - /** Reason why playback is suppressed even though {@link #playWhenReady} is {@code true}. */ - @PlaybackSuppressionReason public final int playbackSuppressionReason; /** * Position up to which media is buffered in {@link #loadingMediaPeriodId) relative to the start @@ -99,8 +94,6 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; TrackGroupArray.EMPTY, emptyTrackSelectorResult, DUMMY_MEDIA_PERIOD_ID, - /* playWhenReady= */ false, - Player.PLAYBACK_SUPPRESSION_REASON_NONE, /* bufferedPositionUs= */ 0, /* totalBufferedDurationUs= */ 0, /* positionUs= */ 0); @@ -131,8 +124,6 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; TrackGroupArray trackGroups, TrackSelectorResult trackSelectorResult, MediaPeriodId loadingMediaPeriodId, - boolean playWhenReady, - @PlaybackSuppressionReason int playbackSuppressionReason, long bufferedPositionUs, long totalBufferedDurationUs, long positionUs) { @@ -145,8 +136,6 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; this.trackGroups = trackGroups; this.trackSelectorResult = trackSelectorResult; this.loadingMediaPeriodId = loadingMediaPeriodId; - this.playWhenReady = playWhenReady; - this.playbackSuppressionReason = playbackSuppressionReason; this.bufferedPositionUs = bufferedPositionUs; this.totalBufferedDurationUs = totalBufferedDurationUs; this.positionUs = positionUs; @@ -188,8 +177,6 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; trackGroups, trackSelectorResult, loadingMediaPeriodId, - playWhenReady, - playbackSuppressionReason, bufferedPositionUs, totalBufferedDurationUs, positionUs); @@ -213,8 +200,6 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; trackGroups, trackSelectorResult, loadingMediaPeriodId, - playWhenReady, - playbackSuppressionReason, bufferedPositionUs, totalBufferedDurationUs, positionUs); @@ -238,8 +223,6 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; trackGroups, trackSelectorResult, loadingMediaPeriodId, - playWhenReady, - playbackSuppressionReason, bufferedPositionUs, totalBufferedDurationUs, positionUs); @@ -263,8 +246,6 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; trackGroups, trackSelectorResult, loadingMediaPeriodId, - playWhenReady, - playbackSuppressionReason, bufferedPositionUs, totalBufferedDurationUs, positionUs); @@ -288,8 +269,6 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; trackGroups, trackSelectorResult, loadingMediaPeriodId, - playWhenReady, - playbackSuppressionReason, bufferedPositionUs, totalBufferedDurationUs, positionUs); @@ -313,37 +292,6 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; trackGroups, trackSelectorResult, loadingMediaPeriodId, - playWhenReady, - playbackSuppressionReason, - bufferedPositionUs, - totalBufferedDurationUs, - positionUs); - } - - /** - * Copies playback info with new information about whether playback should proceed when ready. - * - * @param playWhenReady Whether playback should proceed when {@link #playbackState} == {@link - * Player#STATE_READY}. - * @param playbackSuppressionReason Reason why playback is suppressed even though {@link - * #playWhenReady} is {@code true}. - * @return Copied playback info with new information. - */ - @CheckResult - public PlaybackInfo copyWithPlayWhenReady( - boolean playWhenReady, @PlaybackSuppressionReason int playbackSuppressionReason) { - return new PlaybackInfo( - timeline, - periodId, - requestedContentPositionUs, - playbackState, - playbackError, - isLoading, - trackGroups, - trackSelectorResult, - loadingMediaPeriodId, - playWhenReady, - playbackSuppressionReason, bufferedPositionUs, totalBufferedDurationUs, positionUs); diff --git a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java index ea0e18ca18..e951c67725 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -548,7 +548,6 @@ public final class ExoPlayerTest { // only on seek processed callback). .seek(5) .seek(60) - .waitForSeekProcessed() .play() .build(); final List playbackStatesWhenSeekProcessed = new ArrayList<>(); @@ -2791,7 +2790,6 @@ public final class ExoPlayerTest { .pause() .waitForPlaybackState(Player.STATE_READY) .seek(/* windowIndex= */ 1, /* positionMs= */ 0) - .waitForSeekProcessed() .play() .build(); List trackGroupsList = new ArrayList<>(); diff --git a/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java b/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java index fb424cc92c..5b3b321e09 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java @@ -421,8 +421,6 @@ public final class MediaPeriodQueueTest { /* trackGroups= */ null, /* trackSelectorResult= */ null, /* loadingMediaPeriodId= */ null, - /* playWhenReady= */ false, - Player.PLAYBACK_SUPPRESSION_REASON_NONE, /* bufferedPositionUs= */ 0, /* totalBufferedDurationUs= */ 0, /* positionUs= */ 0); diff --git a/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java b/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java index ac0c444769..f779b70637 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java @@ -315,7 +315,6 @@ public final class AnalyticsCollectorTest { .pause() .waitForPlaybackState(Player.STATE_READY) .seek(/* windowIndex= */ 1, /* positionMs= */ 0) - .waitForSeekProcessed() .play() .build(); TestAnalyticsListener listener = runAnalyticsTest(mediaSource, actionSchedule); @@ -328,8 +327,8 @@ public final class AnalyticsCollectorTest { WINDOW_0 /* setPlayWhenReady=false */, period0 /* READY */, period1 /* BUFFERING */, - period1 /* setPlayWhenReady=true */, period1 /* READY */, + period1 /* setPlayWhenReady=true */, period1 /* ENDED */); assertThat(listener.getEvents(EVENT_TIMELINE_CHANGED)) .containsExactly(WINDOW_0 /* PLAYLIST_CHANGED */, period0 /* SOURCE_UPDATE */); @@ -467,9 +466,6 @@ public final class AnalyticsCollectorTest { .pause() .waitForPlaybackState(Player.STATE_READY) .setMediaSources(/* resetPosition= */ false, mediaSource2) - .waitForTimelineChanged() - // Wait until loading started to prevent flakiness caused by loading finishing too fast. - .waitForIsLoading(true) .play() .build(); TestAnalyticsListener listener = runAnalyticsTest(mediaSource1, actionSchedule); @@ -490,7 +486,7 @@ public final class AnalyticsCollectorTest { WINDOW_0 /* setPlayWhenReady=false */, period0Seq0 /* READY */, WINDOW_0 /* BUFFERING */, - period0Seq1 /* setPlayWhenReady=true */, + WINDOW_0 /* setPlayWhenReady=true */, period0Seq1 /* READY */, period0Seq1 /* ENDED */); assertThat(listener.getEvents(EVENT_TIMELINE_CHANGED)) @@ -549,8 +545,6 @@ public final class AnalyticsCollectorTest { .waitForPlaybackState(Player.STATE_IDLE) .seek(/* positionMs= */ 0) .prepare() - // Wait until loading started to assert loading events without flakiness. - .waitForIsLoading(true) .play() .waitForPlaybackState(Player.STATE_ENDED) .build(); @@ -704,8 +698,6 @@ public final class AnalyticsCollectorTest { .waitForIsLoading(true) .waitForIsLoading(false) .removeMediaItem(/* index= */ 0) - .waitForPlaybackState(Player.STATE_BUFFERING) - .waitForPlaybackState(Player.STATE_READY) .play() .build(); TestAnalyticsListener listener = runAnalyticsTest(fakeMediaSource, actionSchedule); @@ -727,8 +719,8 @@ public final class AnalyticsCollectorTest { WINDOW_0 /* BUFFERING */, period0Seq0 /* READY */, period0Seq1 /* BUFFERING */, - period0Seq1 /* READY */, period0Seq1 /* setPlayWhenReady=true */, + period0Seq1 /* READY */, period0Seq1 /* ENDED */); assertThat(listener.getEvents(EVENT_TIMELINE_CHANGED)) .containsExactly( @@ -823,19 +815,6 @@ public final class AnalyticsCollectorTest { } }) .pause() - // Ensure everything is preloaded. - .waitForIsLoading(true) - .waitForIsLoading(false) - .waitForIsLoading(true) - .waitForIsLoading(false) - .waitForIsLoading(true) - .waitForIsLoading(false) - .waitForIsLoading(true) - .waitForIsLoading(false) - .waitForIsLoading(true) - .waitForIsLoading(false) - .waitForIsLoading(true) - .waitForIsLoading(false) .waitForPlaybackState(Player.STATE_READY) // Wait in each content part to ensure previously triggered events get a chance to be // delivered. This prevents flakiness caused by playback progressing too fast. @@ -1039,8 +1018,6 @@ public final class AnalyticsCollectorTest { .waitForIsLoading(false) // Seek behind the midroll. .seek(6 * C.MICROS_PER_SECOND) - // Wait until loading started again to assert loading events without flakiness. - .waitForIsLoading(true) .play() .waitForPlaybackState(Player.STATE_ENDED) .build(); @@ -1070,8 +1047,8 @@ public final class AnalyticsCollectorTest { WINDOW_0 /* setPlayWhenReady=false */, WINDOW_0 /* BUFFERING */, contentBeforeMidroll /* READY */, + contentAfterMidroll /* setPlayWhenReady=true */, midrollAd /* BUFFERING */, - midrollAd /* setPlayWhenReady=true */, midrollAd /* READY */, contentAfterMidroll /* ENDED */); assertThat(listener.getEvents(EVENT_TIMELINE_CHANGED))