Commit 7b552d77 by tonihei Committed by Oliver Woodman

Move common init steps into SimpleExoPlayer builder.

Some player setup steps that are likely to be only done once
should be moved into the Builder so that player setup can use
a consistent style (builder vs setters).

This also prevents some threading warning issues when the player
is built on a background thread (e.g. for dependency injection
frameworks) and setters can't be used due to threading restrictions.

PiperOrigin-RevId: 311487224
parent ba5871dd
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
* Added `TextComponent.getCurrentCues` because the current cues are no * Added `TextComponent.getCurrentCues` because the current cues are no
longer forwarded to a new `TextOutput` in `SimpleExoPlayer` longer forwarded to a new `TextOutput` in `SimpleExoPlayer`
automatically. automatically.
* Add additional options to `SimpleExoPlayer.Builder` that were previously
only accessible via setters.
* Add opt-in to verify correct thread usage with * Add opt-in to verify correct thread usage with
`SimpleExoPlayer.setThrowsWhenUsingWrongThread(true)` `SimpleExoPlayer.setThrowsWhenUsingWrongThread(true)`
([#4463](https://github.com/google/ExoPlayer/issues/4463)). ([#4463](https://github.com/google/ExoPlayer/issues/4463)).
......
...@@ -146,6 +146,8 @@ public interface ExoPlayer extends Player { ...@@ -146,6 +146,8 @@ public interface ExoPlayer extends Player {
private Looper looper; private Looper looper;
@Nullable private AnalyticsCollector analyticsCollector; @Nullable private AnalyticsCollector analyticsCollector;
private boolean useLazyPreparation; private boolean useLazyPreparation;
private SeekParameters seekParameters;
private boolean pauseAtEndOfMediaItems;
private boolean buildCalled; private boolean buildCalled;
private long releaseTimeoutMs; private long releaseTimeoutMs;
...@@ -166,6 +168,8 @@ public interface ExoPlayer extends Player { ...@@ -166,6 +168,8 @@ public interface ExoPlayer extends Player {
* Looper} * Looper}
* <li>{@link AnalyticsCollector}: {@link AnalyticsCollector} with {@link Clock#DEFAULT} * <li>{@link AnalyticsCollector}: {@link AnalyticsCollector} with {@link Clock#DEFAULT}
* <li>{@code useLazyPreparation}: {@code true} * <li>{@code useLazyPreparation}: {@code true}
* <li>{@link SeekParameters}: {@link SeekParameters#DEFAULT}
* <li>{@code pauseAtEndOfMediaItems}: {@code false}
* <li>{@link Clock}: {@link Clock#DEFAULT} * <li>{@link Clock}: {@link Clock#DEFAULT}
* </ul> * </ul>
* *
...@@ -178,50 +182,37 @@ public interface ExoPlayer extends Player { ...@@ -178,50 +182,37 @@ public interface ExoPlayer extends Player {
new DefaultTrackSelector(context), new DefaultTrackSelector(context),
DefaultMediaSourceFactory.newInstance(context), DefaultMediaSourceFactory.newInstance(context),
new DefaultLoadControl(), new DefaultLoadControl(),
DefaultBandwidthMeter.getSingletonInstance(context), DefaultBandwidthMeter.getSingletonInstance(context));
Util.getLooper(),
/* analyticsCollector= */ null,
/* useLazyPreparation= */ true,
Clock.DEFAULT);
} }
/** /**
* Creates a builder with the specified custom components. * Creates a builder with the specified custom components.
* *
* <p>Note that this constructor is only useful if you try to ensure that ExoPlayer's default * <p>Note that this constructor is only useful to try and ensure that ExoPlayer's default
* components can be removed by ProGuard or R8. For most components except renderers, there is * components can be removed by ProGuard or R8.
* only a marginal benefit of doing that.
* *
* @param renderers The {@link Renderer Renderers} to be used by the player. * @param renderers The {@link Renderer Renderers} to be used by the player.
* @param trackSelector A {@link TrackSelector}. * @param trackSelector A {@link TrackSelector}.
* @param mediaSourceFactory A {@link MediaSourceFactory}. * @param mediaSourceFactory A {@link MediaSourceFactory}.
* @param loadControl A {@link LoadControl}. * @param loadControl A {@link LoadControl}.
* @param bandwidthMeter A {@link BandwidthMeter}. * @param bandwidthMeter A {@link BandwidthMeter}.
* @param looper A {@link Looper} that must be used for all calls to the player.
* @param analyticsCollector An {@link AnalyticsCollector}.
* @param useLazyPreparation Whether media sources should be initialized lazily.
* @param clock A {@link Clock}. Should always be {@link Clock#DEFAULT}.
*/ */
public Builder( public Builder(
Renderer[] renderers, Renderer[] renderers,
TrackSelector trackSelector, TrackSelector trackSelector,
MediaSourceFactory mediaSourceFactory, MediaSourceFactory mediaSourceFactory,
LoadControl loadControl, LoadControl loadControl,
BandwidthMeter bandwidthMeter, BandwidthMeter bandwidthMeter) {
Looper looper,
@Nullable AnalyticsCollector analyticsCollector,
boolean useLazyPreparation,
Clock clock) {
Assertions.checkArgument(renderers.length > 0); Assertions.checkArgument(renderers.length > 0);
this.renderers = renderers; this.renderers = renderers;
this.trackSelector = trackSelector; this.trackSelector = trackSelector;
this.mediaSourceFactory = mediaSourceFactory; this.mediaSourceFactory = mediaSourceFactory;
this.loadControl = loadControl; this.loadControl = loadControl;
this.bandwidthMeter = bandwidthMeter; this.bandwidthMeter = bandwidthMeter;
this.looper = looper; looper = Util.getLooper();
this.analyticsCollector = analyticsCollector; useLazyPreparation = true;
this.useLazyPreparation = useLazyPreparation; seekParameters = SeekParameters.DEFAULT;
this.clock = clock; clock = Clock.DEFAULT;
} }
/** /**
...@@ -348,6 +339,37 @@ public interface ExoPlayer extends Player { ...@@ -348,6 +339,37 @@ public interface ExoPlayer extends Player {
} }
/** /**
* Sets the parameters that control how seek operations are performed.
*
* @param seekParameters The {@link SeekParameters}.
* @return This builder.
* @throws IllegalStateException If {@link #build()} has already been called.
*/
public Builder setSeekParameters(SeekParameters seekParameters) {
Assertions.checkState(!buildCalled);
this.seekParameters = seekParameters;
return this;
}
/**
* Sets whether to pause playback at the end of each media item.
*
* <p>This means the player will pause at the end of each window in the current {@link
* #getCurrentTimeline() timeline}. Listeners will be informed by a call to {@link
* Player.EventListener#onPlayWhenReadyChanged(boolean, int)} with the reason {@link
* Player#PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM} when this happens.
*
* @param pauseAtEndOfMediaItems Whether to pause playback at the end of each media item.
* @return This builder.
* @throws IllegalStateException If {@link #build()} has already been called.
*/
public Builder setPauseAtEndOfMediaItems(boolean pauseAtEndOfMediaItems) {
Assertions.checkState(!buildCalled);
this.pauseAtEndOfMediaItems = pauseAtEndOfMediaItems;
return this;
}
/**
* Sets the {@link Clock} that will be used by the player. Should only be set for testing * Sets the {@link Clock} that will be used by the player. Should only be set for testing
* purposes. * purposes.
* *
...@@ -379,6 +401,8 @@ public interface ExoPlayer extends Player { ...@@ -379,6 +401,8 @@ public interface ExoPlayer extends Player {
bandwidthMeter, bandwidthMeter,
analyticsCollector, analyticsCollector,
useLazyPreparation, useLazyPreparation,
seekParameters,
pauseAtEndOfMediaItems,
clock, clock,
looper); looper);
......
...@@ -258,6 +258,8 @@ public final class ExoPlayerFactory { ...@@ -258,6 +258,8 @@ public final class ExoPlayerFactory {
bandwidthMeter, bandwidthMeter,
/* analyticsCollector= */ null, /* analyticsCollector= */ null,
/* useLazyPreparation= */ true, /* useLazyPreparation= */ true,
SeekParameters.DEFAULT,
/* pauseAtEndOfMediaItems= */ false,
Clock.DEFAULT, Clock.DEFAULT,
applicationLooper); applicationLooper);
} }
......
...@@ -109,6 +109,8 @@ import java.util.concurrent.TimeoutException; ...@@ -109,6 +109,8 @@ import java.util.concurrent.TimeoutException;
* @param useLazyPreparation Whether playlist items are prepared lazily. If false, all manifest * @param useLazyPreparation Whether playlist items are prepared lazily. If false, all manifest
* loads and other initial preparation steps happen immediately. If true, these initial * loads and other initial preparation steps happen immediately. If true, these initial
* preparations are triggered only when the player starts buffering the media. * preparations are triggered only when the player starts buffering the media.
* @param seekParameters The {@link SeekParameters}.
* @param pauseAtEndOfMediaItems Whether to pause playback at the end of each media item.
* @param clock The {@link Clock}. * @param clock The {@link Clock}.
* @param applicationLooper The {@link Looper} that must be used for all calls to the player and * @param applicationLooper The {@link Looper} that must be used for all calls to the player and
* which is used to call listeners on. * which is used to call listeners on.
...@@ -122,6 +124,8 @@ import java.util.concurrent.TimeoutException; ...@@ -122,6 +124,8 @@ import java.util.concurrent.TimeoutException;
BandwidthMeter bandwidthMeter, BandwidthMeter bandwidthMeter,
@Nullable AnalyticsCollector analyticsCollector, @Nullable AnalyticsCollector analyticsCollector,
boolean useLazyPreparation, boolean useLazyPreparation,
SeekParameters seekParameters,
boolean pauseAtEndOfMediaItems,
Clock clock, Clock clock,
Looper applicationLooper) { Looper applicationLooper) {
Log.i(TAG, "Init " + Integer.toHexString(System.identityHashCode(this)) + " [" Log.i(TAG, "Init " + Integer.toHexString(System.identityHashCode(this)) + " ["
...@@ -131,6 +135,8 @@ import java.util.concurrent.TimeoutException; ...@@ -131,6 +135,8 @@ import java.util.concurrent.TimeoutException;
this.trackSelector = checkNotNull(trackSelector); this.trackSelector = checkNotNull(trackSelector);
this.mediaSourceFactory = mediaSourceFactory; this.mediaSourceFactory = mediaSourceFactory;
this.useLazyPreparation = useLazyPreparation; this.useLazyPreparation = useLazyPreparation;
this.seekParameters = seekParameters;
this.pauseAtEndOfMediaItems = pauseAtEndOfMediaItems;
repeatMode = Player.REPEAT_MODE_OFF; repeatMode = Player.REPEAT_MODE_OFF;
listeners = new CopyOnWriteArrayList<>(); listeners = new CopyOnWriteArrayList<>();
mediaSourceHolders = new ArrayList<>(); mediaSourceHolders = new ArrayList<>();
...@@ -142,7 +148,6 @@ import java.util.concurrent.TimeoutException; ...@@ -142,7 +148,6 @@ import java.util.concurrent.TimeoutException;
null); null);
period = new Timeline.Period(); period = new Timeline.Period();
playbackSpeed = Player.DEFAULT_PLAYBACK_SPEED; playbackSpeed = Player.DEFAULT_PLAYBACK_SPEED;
seekParameters = SeekParameters.DEFAULT;
maskingWindowIndex = C.INDEX_UNSET; maskingWindowIndex = C.INDEX_UNSET;
applicationHandler = applicationHandler =
new Handler(applicationLooper) { new Handler(applicationLooper) {
...@@ -166,6 +171,8 @@ import java.util.concurrent.TimeoutException; ...@@ -166,6 +171,8 @@ import java.util.concurrent.TimeoutException;
repeatMode, repeatMode,
shuffleModeEnabled, shuffleModeEnabled,
analyticsCollector, analyticsCollector,
seekParameters,
pauseAtEndOfMediaItems,
applicationHandler, applicationHandler,
clock); clock);
internalPlayerHandler = new Handler(internalPlayer.getPlaybackLooper()); internalPlayerHandler = new Handler(internalPlayer.getPlaybackLooper());
......
...@@ -146,6 +146,8 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -146,6 +146,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
@Player.RepeatMode int repeatMode, @Player.RepeatMode int repeatMode,
boolean shuffleModeEnabled, boolean shuffleModeEnabled,
@Nullable AnalyticsCollector analyticsCollector, @Nullable AnalyticsCollector analyticsCollector,
SeekParameters seekParameters,
boolean pauseAtEndOfWindow,
Handler eventHandler, Handler eventHandler,
Clock clock) { Clock clock) {
this.renderers = renderers; this.renderers = renderers;
...@@ -155,6 +157,8 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -155,6 +157,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
this.bandwidthMeter = bandwidthMeter; this.bandwidthMeter = bandwidthMeter;
this.repeatMode = repeatMode; this.repeatMode = repeatMode;
this.shuffleModeEnabled = shuffleModeEnabled; this.shuffleModeEnabled = shuffleModeEnabled;
this.seekParameters = seekParameters;
this.pauseAtEndOfWindow = pauseAtEndOfWindow;
this.eventHandler = eventHandler; this.eventHandler = eventHandler;
this.clock = clock; this.clock = clock;
this.queue = new MediaPeriodQueue(); this.queue = new MediaPeriodQueue();
...@@ -162,7 +166,6 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -162,7 +166,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
backBufferDurationUs = loadControl.getBackBufferDurationUs(); backBufferDurationUs = loadControl.getBackBufferDurationUs();
retainBackBufferFromKeyframe = loadControl.retainBackBufferFromKeyframe(); retainBackBufferFromKeyframe = loadControl.retainBackBufferFromKeyframe();
seekParameters = SeekParameters.DEFAULT;
playbackInfo = PlaybackInfo.createDummy(emptyTrackSelectorResult); playbackInfo = PlaybackInfo.createDummy(emptyTrackSelectorResult);
playbackInfoUpdate = new PlaybackInfoUpdate(playbackInfo); playbackInfoUpdate = new PlaybackInfoUpdate(playbackInfo);
rendererCapabilities = new RendererCapabilities[renderers.length]; rendererCapabilities = new RendererCapabilities[renderers.length];
......
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