Commit 61935e14 by tonihei Committed by Oliver Woodman

Add option to pause at end of stream to ExoPlayerImplInternal

This option marks streams as final such that renderers play them out
completely, then waits until this happened, and then sets the player
to paused. After that, the player can continue to read the next period
to quickly resume playback if needed.

PiperOrigin-RevId: 298824745
parent e88e889c
...@@ -88,6 +88,7 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -88,6 +88,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
private static final int MSG_REMOVE_MEDIA_SOURCES = 20; private static final int MSG_REMOVE_MEDIA_SOURCES = 20;
private static final int MSG_SET_SHUFFLE_ORDER = 21; private static final int MSG_SET_SHUFFLE_ORDER = 21;
private static final int MSG_PLAYLIST_UPDATE_REQUESTED = 22; private static final int MSG_PLAYLIST_UPDATE_REQUESTED = 22;
private static final int MSG_SET_PAUSE_AT_END_OF_WINDOW = 23;
private static final int ACTIVE_INTERVAL_MS = 10; private static final int ACTIVE_INTERVAL_MS = 10;
private static final int IDLE_INTERVAL_MS = 1000; private static final int IDLE_INTERVAL_MS = 1000;
...@@ -119,6 +120,8 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -119,6 +120,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
private Renderer[] enabledRenderers; private Renderer[] enabledRenderers;
private boolean released; private boolean released;
private boolean playWhenReady; private boolean playWhenReady;
private boolean pauseAtEndOfWindow;
private boolean pendingPauseAtEndOfPeriod;
private boolean rebuffering; private boolean rebuffering;
private boolean shouldContinueLoading; private boolean shouldContinueLoading;
@Player.RepeatMode private int repeatMode; @Player.RepeatMode private int repeatMode;
...@@ -199,6 +202,12 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -199,6 +202,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
handler.obtainMessage(MSG_SET_PLAY_WHEN_READY, playWhenReady ? 1 : 0, 0).sendToTarget(); handler.obtainMessage(MSG_SET_PLAY_WHEN_READY, playWhenReady ? 1 : 0, 0).sendToTarget();
} }
public void setPauseAtEndOfWindow(boolean pauseAtEndOfWindow) {
handler
.obtainMessage(MSG_SET_PAUSE_AT_END_OF_WINDOW, pauseAtEndOfWindow ? 1 : 0, /* ignored */ 0)
.sendToTarget();
}
public void setRepeatMode(@Player.RepeatMode int repeatMode) { public void setRepeatMode(@Player.RepeatMode int repeatMode) {
handler.obtainMessage(MSG_SET_REPEAT_MODE, repeatMode, 0).sendToTarget(); handler.obtainMessage(MSG_SET_REPEAT_MODE, repeatMode, 0).sendToTarget();
} }
...@@ -439,6 +448,9 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -439,6 +448,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
case MSG_PLAYLIST_UPDATE_REQUESTED: case MSG_PLAYLIST_UPDATE_REQUESTED:
playlistUpdateRequestedInternal(); playlistUpdateRequestedInternal();
break; break;
case MSG_SET_PAUSE_AT_END_OF_WINDOW:
setPauseAtEndOfWindowInternal(msg.arg1 != 0);
break;
case MSG_RELEASE: case MSG_RELEASE:
releaseInternal(); releaseInternal();
// Return immediately to not send playback info updates after release. // Return immediately to not send playback info updates after release.
...@@ -660,6 +672,16 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -660,6 +672,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
} }
} }
private void setPauseAtEndOfWindowInternal(boolean pauseAtEndOfWindow)
throws ExoPlaybackException {
this.pauseAtEndOfWindow = pauseAtEndOfWindow;
if (queue.getReadingPeriod() != queue.getPlayingPeriod()) {
seekToCurrentPosition(/* sendDiscontinuity= */ true);
}
resetPendingPauseAtEndOfPeriod();
handleLoadingMediaPeriodChanged(/* loadingTrackSelectionChanged= */ false);
}
private void setRepeatModeInternal(@Player.RepeatMode int repeatMode) private void setRepeatModeInternal(@Player.RepeatMode int repeatMode)
throws ExoPlaybackException { throws ExoPlaybackException {
this.repeatMode = repeatMode; this.repeatMode = repeatMode;
...@@ -810,11 +832,16 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -810,11 +832,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
} }
long playingPeriodDurationUs = playingPeriodHolder.info.durationUs; long playingPeriodDurationUs = playingPeriodHolder.info.durationUs;
if (renderersEnded boolean finishedRendering =
&& playingPeriodHolder.prepared renderersEnded
&& (playingPeriodDurationUs == C.TIME_UNSET && playingPeriodHolder.prepared
|| playingPeriodDurationUs <= playbackInfo.positionUs) && (playingPeriodDurationUs == C.TIME_UNSET
&& playingPeriodHolder.info.isFinal) { || playingPeriodDurationUs <= playbackInfo.positionUs);
if (finishedRendering && pendingPauseAtEndOfPeriod) {
pendingPauseAtEndOfPeriod = false;
setPlayWhenReadyInternal(false);
}
if (finishedRendering && playingPeriodHolder.info.isFinal) {
setState(Player.STATE_ENDED); setState(Player.STATE_ENDED);
stopRenderers(); stopRenderers();
} else if (playbackInfo.playbackState == Player.STATE_BUFFERING } else if (playbackInfo.playbackState == Player.STATE_BUFFERING
...@@ -1571,6 +1598,7 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -1571,6 +1598,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
playbackInfo = playbackInfo =
copyWithNewPosition(newPeriodId, newPositionUs, newRequestedContentPositionUs); copyWithNewPosition(newPeriodId, newPositionUs, newRequestedContentPositionUs);
} }
resetPendingPauseAtEndOfPeriod();
resolvePendingMessagePositions( resolvePendingMessagePositions(
/* newTimeline= */ timeline, /* previousTimeline= */ playbackInfo.timeline); /* newTimeline= */ timeline, /* previousTimeline= */ playbackInfo.timeline);
playbackInfo = playbackInfo.copyWithTimeline(timeline); playbackInfo = playbackInfo.copyWithTimeline(timeline);
...@@ -1656,9 +1684,10 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -1656,9 +1684,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
return; return;
} }
if (readingPeriodHolder.getNext() == null) { if (readingPeriodHolder.getNext() == null || pendingPauseAtEndOfPeriod) {
// We don't have a successor to advance the reading period to. // We don't have a successor to advance the reading period to or we want to let them end
if (readingPeriodHolder.info.isFinal) { // intentionally to pause at the end of the period.
if (readingPeriodHolder.info.isFinal || pendingPauseAtEndOfPeriod) {
for (int i = 0; i < renderers.length; i++) { for (int i = 0; i < renderers.length; i++) {
Renderer renderer = renderers[i]; Renderer renderer = renderers[i];
SampleStream sampleStream = readingPeriodHolder.sampleStreams[i]; SampleStream sampleStream = readingPeriodHolder.sampleStreams[i];
...@@ -1754,16 +1783,26 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -1754,16 +1783,26 @@ import java.util.concurrent.atomic.AtomicBoolean;
? Player.DISCONTINUITY_REASON_PERIOD_TRANSITION ? Player.DISCONTINUITY_REASON_PERIOD_TRANSITION
: Player.DISCONTINUITY_REASON_AD_INSERTION; : Player.DISCONTINUITY_REASON_AD_INSERTION;
playbackInfoUpdate.setPositionDiscontinuity(discontinuityReason); playbackInfoUpdate.setPositionDiscontinuity(discontinuityReason);
resetPendingPauseAtEndOfPeriod();
enablePlayingPeriodRenderers(rendererWasEnabledFlags); enablePlayingPeriodRenderers(rendererWasEnabledFlags);
updatePlaybackPositions(); updatePlaybackPositions();
advancedPlayingPeriod = true; advancedPlayingPeriod = true;
} }
} }
private void resetPendingPauseAtEndOfPeriod() {
@Nullable MediaPeriodHolder playingPeriod = queue.getPlayingPeriod();
pendingPauseAtEndOfPeriod =
playingPeriod != null && playingPeriod.info.isLastInTimelineWindow && pauseAtEndOfWindow;
}
private boolean shouldAdvancePlayingPeriod() { private boolean shouldAdvancePlayingPeriod() {
if (!playWhenReady) { if (!playWhenReady) {
return false; return false;
} }
if (pendingPauseAtEndOfPeriod) {
return false;
}
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod(); MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
if (playingPeriodHolder == null) { if (playingPeriodHolder == null) {
return false; return false;
...@@ -1904,6 +1943,7 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -1904,6 +1943,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
deliverPendingMessageAtStartPositionRequired deliverPendingMessageAtStartPositionRequired
|| positionUs != playbackInfo.positionUs || positionUs != playbackInfo.positionUs
|| !mediaPeriodId.equals(playbackInfo.periodId); || !mediaPeriodId.equals(playbackInfo.periodId);
resetPendingPauseAtEndOfPeriod();
TrackGroupArray trackGroupArray = playbackInfo.trackGroups; TrackGroupArray trackGroupArray = playbackInfo.trackGroups;
TrackSelectorResult trackSelectorResult = playbackInfo.trackSelectorResult; TrackSelectorResult trackSelectorResult = playbackInfo.trackSelectorResult;
if (playlist.isPrepared()) { if (playlist.isPrepared()) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment