Commit 27383068 by tonihei Committed by Ian Baker

Make ExoPlayerImpl an ExoPlayer implementation

All the functionality of SimpleExoPlayer has moved to ExoPlayerImpl.
Hence, ExoPlayerImpl can fulfil its own name and become an ExoPlayer
implementation. As a result, ExoPlayer.Builder can return ExoPlayerImpl
directly without using SimpleExoPlayer at all.

#minor-release

PiperOrigin-RevId: 427947028
parent 8d09da4a
...@@ -1018,7 +1018,9 @@ public interface ExoPlayer extends Player { ...@@ -1018,7 +1018,9 @@ public interface ExoPlayer extends Player {
* @throws IllegalStateException If this method has already been called. * @throws IllegalStateException If this method has already been called.
*/ */
public ExoPlayer build() { public ExoPlayer build() {
return buildSimpleExoPlayer(); checkState(!buildCalled);
buildCalled = true;
return new ExoPlayerImpl(/* builder= */ this, /* wrappingPlayer= */ null);
} }
/* package */ SimpleExoPlayer buildSimpleExoPlayer() { /* package */ SimpleExoPlayer buildSimpleExoPlayer() {
......
...@@ -18,59 +18,6 @@ package androidx.media3.exoplayer; ...@@ -18,59 +18,6 @@ package androidx.media3.exoplayer;
import static androidx.media3.common.C.TRACK_TYPE_AUDIO; import static androidx.media3.common.C.TRACK_TYPE_AUDIO;
import static androidx.media3.common.C.TRACK_TYPE_CAMERA_MOTION; import static androidx.media3.common.C.TRACK_TYPE_CAMERA_MOTION;
import static androidx.media3.common.C.TRACK_TYPE_VIDEO; import static androidx.media3.common.C.TRACK_TYPE_VIDEO;
import static androidx.media3.common.Player.COMMAND_ADJUST_DEVICE_VOLUME;
import static androidx.media3.common.Player.COMMAND_CHANGE_MEDIA_ITEMS;
import static androidx.media3.common.Player.COMMAND_GET_AUDIO_ATTRIBUTES;
import static androidx.media3.common.Player.COMMAND_GET_CURRENT_MEDIA_ITEM;
import static androidx.media3.common.Player.COMMAND_GET_DEVICE_VOLUME;
import static androidx.media3.common.Player.COMMAND_GET_MEDIA_ITEMS_METADATA;
import static androidx.media3.common.Player.COMMAND_GET_TEXT;
import static androidx.media3.common.Player.COMMAND_GET_TIMELINE;
import static androidx.media3.common.Player.COMMAND_GET_TRACK_INFOS;
import static androidx.media3.common.Player.COMMAND_GET_VOLUME;
import static androidx.media3.common.Player.COMMAND_PLAY_PAUSE;
import static androidx.media3.common.Player.COMMAND_PREPARE;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_DEFAULT_POSITION;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_MEDIA_ITEM;
import static androidx.media3.common.Player.COMMAND_SET_DEVICE_VOLUME;
import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEMS_METADATA;
import static androidx.media3.common.Player.COMMAND_SET_REPEAT_MODE;
import static androidx.media3.common.Player.COMMAND_SET_SHUFFLE_MODE;
import static androidx.media3.common.Player.COMMAND_SET_SPEED_AND_PITCH;
import static androidx.media3.common.Player.COMMAND_SET_TRACK_SELECTION_PARAMETERS;
import static androidx.media3.common.Player.COMMAND_SET_VIDEO_SURFACE;
import static androidx.media3.common.Player.COMMAND_SET_VOLUME;
import static androidx.media3.common.Player.COMMAND_STOP;
import static androidx.media3.common.Player.DISCONTINUITY_REASON_AUTO_TRANSITION;
import static androidx.media3.common.Player.DISCONTINUITY_REASON_INTERNAL;
import static androidx.media3.common.Player.DISCONTINUITY_REASON_REMOVE;
import static androidx.media3.common.Player.DISCONTINUITY_REASON_SEEK;
import static androidx.media3.common.Player.EVENT_AUDIO_ATTRIBUTES_CHANGED;
import static androidx.media3.common.Player.EVENT_AUDIO_SESSION_ID;
import static androidx.media3.common.Player.EVENT_CUES;
import static androidx.media3.common.Player.EVENT_DEVICE_INFO_CHANGED;
import static androidx.media3.common.Player.EVENT_DEVICE_VOLUME_CHANGED;
import static androidx.media3.common.Player.EVENT_MEDIA_METADATA_CHANGED;
import static androidx.media3.common.Player.EVENT_METADATA;
import static androidx.media3.common.Player.EVENT_PLAYLIST_METADATA_CHANGED;
import static androidx.media3.common.Player.EVENT_RENDERED_FIRST_FRAME;
import static androidx.media3.common.Player.EVENT_SKIP_SILENCE_ENABLED_CHANGED;
import static androidx.media3.common.Player.EVENT_SURFACE_SIZE_CHANGED;
import static androidx.media3.common.Player.EVENT_TRACK_SELECTION_PARAMETERS_CHANGED;
import static androidx.media3.common.Player.EVENT_VIDEO_SIZE_CHANGED;
import static androidx.media3.common.Player.EVENT_VOLUME_CHANGED;
import static androidx.media3.common.Player.MEDIA_ITEM_TRANSITION_REASON_AUTO;
import static androidx.media3.common.Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED;
import static androidx.media3.common.Player.MEDIA_ITEM_TRANSITION_REASON_REPEAT;
import static androidx.media3.common.Player.MEDIA_ITEM_TRANSITION_REASON_SEEK;
import static androidx.media3.common.Player.PLAYBACK_SUPPRESSION_REASON_NONE;
import static androidx.media3.common.Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS;
import static androidx.media3.common.Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST;
import static androidx.media3.common.Player.STATE_BUFFERING;
import static androidx.media3.common.Player.STATE_ENDED;
import static androidx.media3.common.Player.STATE_IDLE;
import static androidx.media3.common.Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED;
import static androidx.media3.common.Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Util.castNonNull; import static androidx.media3.common.util.Util.castNonNull;
...@@ -107,6 +54,7 @@ import androidx.annotation.Nullable; ...@@ -107,6 +54,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.media3.common.AudioAttributes; import androidx.media3.common.AudioAttributes;
import androidx.media3.common.AuxEffectInfo; import androidx.media3.common.AuxEffectInfo;
import androidx.media3.common.BasePlayer;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.DeviceInfo; import androidx.media3.common.DeviceInfo;
import androidx.media3.common.Format; import androidx.media3.common.Format;
...@@ -118,16 +66,6 @@ import androidx.media3.common.Metadata; ...@@ -118,16 +66,6 @@ import androidx.media3.common.Metadata;
import androidx.media3.common.PlaybackException; import androidx.media3.common.PlaybackException;
import androidx.media3.common.PlaybackParameters; import androidx.media3.common.PlaybackParameters;
import androidx.media3.common.Player; import androidx.media3.common.Player;
import androidx.media3.common.Player.Commands;
import androidx.media3.common.Player.DiscontinuityReason;
import androidx.media3.common.Player.Events;
import androidx.media3.common.Player.Listener;
import androidx.media3.common.Player.PlayWhenReadyChangeReason;
import androidx.media3.common.Player.PlaybackSuppressionReason;
import androidx.media3.common.Player.PositionInfo;
import androidx.media3.common.Player.RepeatMode;
import androidx.media3.common.Player.State;
import androidx.media3.common.Player.TimelineChangeReason;
import androidx.media3.common.PriorityTaskManager; import androidx.media3.common.PriorityTaskManager;
import androidx.media3.common.Timeline; import androidx.media3.common.Timeline;
import androidx.media3.common.TrackGroup; import androidx.media3.common.TrackGroup;
...@@ -144,7 +82,6 @@ import androidx.media3.common.util.HandlerWrapper; ...@@ -144,7 +82,6 @@ import androidx.media3.common.util.HandlerWrapper;
import androidx.media3.common.util.ListenerSet; import androidx.media3.common.util.ListenerSet;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.ExoPlayer.AudioOffloadListener;
import androidx.media3.exoplayer.PlayerMessage.Target; import androidx.media3.exoplayer.PlayerMessage.Target;
import androidx.media3.exoplayer.Renderer.MessageType; import androidx.media3.exoplayer.Renderer.MessageType;
import androidx.media3.exoplayer.analytics.AnalyticsCollector; import androidx.media3.exoplayer.analytics.AnalyticsCollector;
...@@ -173,8 +110,13 @@ import java.util.List; ...@@ -173,8 +110,13 @@ import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
/** A helper class for the {@link SimpleExoPlayer} implementation of {@link ExoPlayer}. */ /** The default implementation of {@link ExoPlayer}. */
/* package */ final class ExoPlayerImpl { /* package */ final class ExoPlayerImpl extends BasePlayer
implements ExoPlayer,
ExoPlayer.AudioComponent,
ExoPlayer.VideoComponent,
ExoPlayer.TextComponent,
ExoPlayer.DeviceComponent {
static { static {
MediaLibraryInfo.registerModule("media3.exoplayer"); MediaLibraryInfo.registerModule("media3.exoplayer");
...@@ -204,7 +146,6 @@ import java.util.concurrent.TimeoutException; ...@@ -204,7 +146,6 @@ import java.util.concurrent.TimeoutException;
private final ListenerSet<Listener> listeners; private final ListenerSet<Listener> listeners;
private final CopyOnWriteArraySet<AudioOffloadListener> audioOffloadListeners; private final CopyOnWriteArraySet<AudioOffloadListener> audioOffloadListeners;
private final Timeline.Period period; private final Timeline.Period period;
private final Timeline.Window window;
private final List<MediaSourceHolderSnapshot> mediaSourceHolderSnapshots; private final List<MediaSourceHolderSnapshot> mediaSourceHolderSnapshots;
private final boolean useLazyPreparation; private final boolean useLazyPreparation;
private final MediaSource.Factory mediaSourceFactory; private final MediaSource.Factory mediaSourceFactory;
...@@ -279,7 +220,7 @@ import java.util.concurrent.TimeoutException; ...@@ -279,7 +220,7 @@ import java.util.concurrent.TimeoutException;
private long maskingWindowPositionMs; private long maskingWindowPositionMs;
@SuppressLint("HandlerLeak") @SuppressLint("HandlerLeak")
public ExoPlayerImpl(ExoPlayer.Builder builder, Player wrappingPlayer) { public ExoPlayerImpl(ExoPlayer.Builder builder, @Nullable Player wrappingPlayer) {
constructorFinished = new ConditionVariable(); constructorFinished = new ConditionVariable();
try { try {
Log.i( Log.i(
...@@ -323,12 +264,12 @@ import java.util.concurrent.TimeoutException; ...@@ -323,12 +264,12 @@ import java.util.concurrent.TimeoutException;
this.pauseAtEndOfMediaItems = builder.pauseAtEndOfMediaItems; this.pauseAtEndOfMediaItems = builder.pauseAtEndOfMediaItems;
this.applicationLooper = builder.looper; this.applicationLooper = builder.looper;
this.clock = builder.clock; this.clock = builder.clock;
this.wrappingPlayer = wrappingPlayer; this.wrappingPlayer = wrappingPlayer == null ? this : wrappingPlayer;
listeners = listeners =
new ListenerSet<>( new ListenerSet<>(
applicationLooper, applicationLooper,
clock, clock,
(listener, flags) -> listener.onEvents(wrappingPlayer, new Events(flags))); (listener, flags) -> listener.onEvents(this.wrappingPlayer, new Events(flags)));
audioOffloadListeners = new CopyOnWriteArraySet<>(); audioOffloadListeners = new CopyOnWriteArraySet<>();
mediaSourceHolderSnapshots = new ArrayList<>(); mediaSourceHolderSnapshots = new ArrayList<>();
shuffleOrder = new ShuffleOrder.DefaultShuffleOrder(/* length= */ 0); shuffleOrder = new ShuffleOrder.DefaultShuffleOrder(/* length= */ 0);
...@@ -339,7 +280,6 @@ import java.util.concurrent.TimeoutException; ...@@ -339,7 +280,6 @@ import java.util.concurrent.TimeoutException;
TracksInfo.EMPTY, TracksInfo.EMPTY,
/* info= */ null); /* info= */ null);
period = new Timeline.Period(); period = new Timeline.Period();
window = new Timeline.Window();
permanentAvailableCommands = permanentAvailableCommands =
new Commands.Builder() new Commands.Builder()
.addAll( .addAll(
...@@ -377,7 +317,7 @@ import java.util.concurrent.TimeoutException; ...@@ -377,7 +317,7 @@ import java.util.concurrent.TimeoutException;
playbackInfoUpdate -> playbackInfoUpdate ->
playbackInfoUpdateHandler.post(() -> handlePlaybackInfo(playbackInfoUpdate)); playbackInfoUpdateHandler.post(() -> handlePlaybackInfo(playbackInfoUpdate));
playbackInfo = PlaybackInfo.createDummy(emptyTrackSelectorResult); playbackInfo = PlaybackInfo.createDummy(emptyTrackSelectorResult);
analyticsCollector.setPlayer(wrappingPlayer, applicationLooper); analyticsCollector.setPlayer(this.wrappingPlayer, applicationLooper);
PlayerId playerId = PlayerId playerId =
Util.SDK_INT < 31 Util.SDK_INT < 31
? new PlayerId() ? new PlayerId()
...@@ -420,7 +360,7 @@ import java.util.concurrent.TimeoutException; ...@@ -420,7 +360,7 @@ import java.util.concurrent.TimeoutException;
bandwidthMeter.addEventListener(new Handler(applicationLooper), analyticsCollector); bandwidthMeter.addEventListener(new Handler(applicationLooper), analyticsCollector);
addAudioOffloadListener(componentListener); addAudioOffloadListener(componentListener);
if (builder.foregroundModeTimeoutMs > 0) { if (builder.foregroundModeTimeoutMs > 0) {
experimentalSetForegroundModeTimeoutMs(builder.foregroundModeTimeoutMs); internalPlayer.experimentalSetForegroundModeTimeoutMs(builder.foregroundModeTimeoutMs);
} }
audioBecomingNoisyManager = audioBecomingNoisyManager =
...@@ -454,82 +394,108 @@ import java.util.concurrent.TimeoutException; ...@@ -454,82 +394,108 @@ import java.util.concurrent.TimeoutException;
} }
} }
/** @SuppressWarnings("deprecation") // Returning deprecated class.
* Sets a limit on the time a call to {@link #setForegroundMode} can spend. If a call to {@link @Override
* #setForegroundMode} takes more than {@code timeoutMs} milliseconds to complete, the player will @Deprecated
* raise an error via {@link Player.Listener#onPlayerError}. public AudioComponent getAudioComponent() {
* return this;
* <p>This method is experimental, and will be renamed or removed in a future release. It should
* only be called before the player is used.
*
* @param timeoutMs The time limit in milliseconds.
*/
public void experimentalSetForegroundModeTimeoutMs(long timeoutMs) {
internalPlayer.experimentalSetForegroundModeTimeoutMs(timeoutMs);
} }
@SuppressWarnings("deprecation") // Returning deprecated class.
@Override
@Deprecated
public VideoComponent getVideoComponent() {
return this;
}
@SuppressWarnings("deprecation") // Returning deprecated class.
@Override
@Deprecated
public TextComponent getTextComponent() {
return this;
}
@SuppressWarnings("deprecation") // Returning deprecated class.
@Override
@Deprecated
public DeviceComponent getDeviceComponent() {
return this;
}
@Override
public void experimentalSetOffloadSchedulingEnabled(boolean offloadSchedulingEnabled) { public void experimentalSetOffloadSchedulingEnabled(boolean offloadSchedulingEnabled) {
verifyApplicationThread(); verifyApplicationThread();
internalPlayer.experimentalSetOffloadSchedulingEnabled(offloadSchedulingEnabled); internalPlayer.experimentalSetOffloadSchedulingEnabled(offloadSchedulingEnabled);
} }
@Override
public boolean experimentalIsSleepingForOffload() { public boolean experimentalIsSleepingForOffload() {
verifyApplicationThread(); verifyApplicationThread();
return playbackInfo.sleepingForOffload; return playbackInfo.sleepingForOffload;
} }
@Override
public Looper getPlaybackLooper() { public Looper getPlaybackLooper() {
// Don't verify application thread. We allow calls to this method from any thread. // Don't verify application thread. We allow calls to this method from any thread.
return internalPlayer.getPlaybackLooper(); return internalPlayer.getPlaybackLooper();
} }
@Override
public Looper getApplicationLooper() { public Looper getApplicationLooper() {
// Don't verify application thread. We allow calls to this method from any thread. // Don't verify application thread. We allow calls to this method from any thread.
return applicationLooper; return applicationLooper;
} }
@Override
public Clock getClock() { public Clock getClock() {
// Don't verify application thread. We allow calls to this method from any thread. // Don't verify application thread. We allow calls to this method from any thread.
return clock; return clock;
} }
@Override
public void addAudioOffloadListener(AudioOffloadListener listener) { public void addAudioOffloadListener(AudioOffloadListener listener) {
// Don't verify application thread. We allow calls to this method from any thread. // Don't verify application thread. We allow calls to this method from any thread.
audioOffloadListeners.add(listener); audioOffloadListeners.add(listener);
} }
@Override
public void removeAudioOffloadListener(AudioOffloadListener listener) { public void removeAudioOffloadListener(AudioOffloadListener listener) {
// Don't verify application thread. We allow calls to this method from any thread. // Don't verify application thread. We allow calls to this method from any thread.
audioOffloadListeners.remove(listener); audioOffloadListeners.remove(listener);
} }
@Override
public Commands getAvailableCommands() { public Commands getAvailableCommands() {
verifyApplicationThread(); verifyApplicationThread();
return availableCommands; return availableCommands;
} }
@Override
public @State int getPlaybackState() { public @State int getPlaybackState() {
verifyApplicationThread(); verifyApplicationThread();
return playbackInfo.playbackState; return playbackInfo.playbackState;
} }
@Override
public @PlaybackSuppressionReason int getPlaybackSuppressionReason() { public @PlaybackSuppressionReason int getPlaybackSuppressionReason() {
verifyApplicationThread(); verifyApplicationThread();
return playbackInfo.playbackSuppressionReason; return playbackInfo.playbackSuppressionReason;
} }
@Override
@Nullable @Nullable
public ExoPlaybackException getPlayerError() { public ExoPlaybackException getPlayerError() {
verifyApplicationThread(); verifyApplicationThread();
return playbackInfo.playbackError; return playbackInfo.playbackError;
} }
/** @deprecated Use {@link #prepare()} instead. */ @Override
@Deprecated @Deprecated
public void retry() { public void retry() {
prepare(); prepare();
} }
@Override
public void prepare() { public void prepare() {
verifyApplicationThread(); verifyApplicationThread();
boolean playWhenReady = getPlayWhenReady(); boolean playWhenReady = getPlayWhenReady();
...@@ -561,9 +527,7 @@ import java.util.concurrent.TimeoutException; ...@@ -561,9 +527,7 @@ import java.util.concurrent.TimeoutException;
/* ignored */ C.INDEX_UNSET); /* ignored */ C.INDEX_UNSET);
} }
/** @Override
* @deprecated Use {@link #setMediaSource(MediaSource)} and {@link ExoPlayer#prepare()} instead.
*/
@Deprecated @Deprecated
public void prepare(MediaSource mediaSource) { public void prepare(MediaSource mediaSource) {
verifyApplicationThread(); verifyApplicationThread();
...@@ -571,10 +535,7 @@ import java.util.concurrent.TimeoutException; ...@@ -571,10 +535,7 @@ import java.util.concurrent.TimeoutException;
prepare(); prepare();
} }
/** @Override
* @deprecated Use {@link #setMediaSource(MediaSource, boolean)} and {@link ExoPlayer#prepare()}
* instead.
*/
@Deprecated @Deprecated
public void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState) { public void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState) {
verifyApplicationThread(); verifyApplicationThread();
...@@ -582,37 +543,44 @@ import java.util.concurrent.TimeoutException; ...@@ -582,37 +543,44 @@ import java.util.concurrent.TimeoutException;
prepare(); prepare();
} }
@Override
public void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition) { public void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition) {
verifyApplicationThread(); verifyApplicationThread();
setMediaSources(createMediaSources(mediaItems), resetPosition); setMediaSources(createMediaSources(mediaItems), resetPosition);
} }
@Override
public void setMediaItems(List<MediaItem> mediaItems, int startIndex, long startPositionMs) { public void setMediaItems(List<MediaItem> mediaItems, int startIndex, long startPositionMs) {
verifyApplicationThread(); verifyApplicationThread();
setMediaSources(createMediaSources(mediaItems), startIndex, startPositionMs); setMediaSources(createMediaSources(mediaItems), startIndex, startPositionMs);
} }
@Override
public void setMediaSource(MediaSource mediaSource) { public void setMediaSource(MediaSource mediaSource) {
verifyApplicationThread(); verifyApplicationThread();
setMediaSources(Collections.singletonList(mediaSource)); setMediaSources(Collections.singletonList(mediaSource));
} }
@Override
public void setMediaSource(MediaSource mediaSource, long startPositionMs) { public void setMediaSource(MediaSource mediaSource, long startPositionMs) {
verifyApplicationThread(); verifyApplicationThread();
setMediaSources( setMediaSources(
Collections.singletonList(mediaSource), /* startWindowIndex= */ 0, startPositionMs); Collections.singletonList(mediaSource), /* startWindowIndex= */ 0, startPositionMs);
} }
@Override
public void setMediaSource(MediaSource mediaSource, boolean resetPosition) { public void setMediaSource(MediaSource mediaSource, boolean resetPosition) {
verifyApplicationThread(); verifyApplicationThread();
setMediaSources(Collections.singletonList(mediaSource), resetPosition); setMediaSources(Collections.singletonList(mediaSource), resetPosition);
} }
@Override
public void setMediaSources(List<MediaSource> mediaSources) { public void setMediaSources(List<MediaSource> mediaSources) {
verifyApplicationThread(); verifyApplicationThread();
setMediaSources(mediaSources, /* resetPosition= */ true); setMediaSources(mediaSources, /* resetPosition= */ true);
} }
@Override
public void setMediaSources(List<MediaSource> mediaSources, boolean resetPosition) { public void setMediaSources(List<MediaSource> mediaSources, boolean resetPosition) {
verifyApplicationThread(); verifyApplicationThread();
setMediaSourcesInternal( setMediaSourcesInternal(
...@@ -622,6 +590,7 @@ import java.util.concurrent.TimeoutException; ...@@ -622,6 +590,7 @@ import java.util.concurrent.TimeoutException;
/* resetToDefaultPosition= */ resetPosition); /* resetToDefaultPosition= */ resetPosition);
} }
@Override
public void setMediaSources( public void setMediaSources(
List<MediaSource> mediaSources, int startWindowIndex, long startPositionMs) { List<MediaSource> mediaSources, int startWindowIndex, long startPositionMs) {
verifyApplicationThread(); verifyApplicationThread();
...@@ -629,27 +598,32 @@ import java.util.concurrent.TimeoutException; ...@@ -629,27 +598,32 @@ import java.util.concurrent.TimeoutException;
mediaSources, startWindowIndex, startPositionMs, /* resetToDefaultPosition= */ false); mediaSources, startWindowIndex, startPositionMs, /* resetToDefaultPosition= */ false);
} }
@Override
public void addMediaItems(int index, List<MediaItem> mediaItems) { public void addMediaItems(int index, List<MediaItem> mediaItems) {
verifyApplicationThread(); verifyApplicationThread();
index = min(index, mediaSourceHolderSnapshots.size()); index = min(index, mediaSourceHolderSnapshots.size());
addMediaSources(index, createMediaSources(mediaItems)); addMediaSources(index, createMediaSources(mediaItems));
} }
@Override
public void addMediaSource(MediaSource mediaSource) { public void addMediaSource(MediaSource mediaSource) {
verifyApplicationThread(); verifyApplicationThread();
addMediaSources(Collections.singletonList(mediaSource)); addMediaSources(Collections.singletonList(mediaSource));
} }
@Override
public void addMediaSource(int index, MediaSource mediaSource) { public void addMediaSource(int index, MediaSource mediaSource) {
verifyApplicationThread(); verifyApplicationThread();
addMediaSources(index, Collections.singletonList(mediaSource)); addMediaSources(index, Collections.singletonList(mediaSource));
} }
@Override
public void addMediaSources(List<MediaSource> mediaSources) { public void addMediaSources(List<MediaSource> mediaSources) {
verifyApplicationThread(); verifyApplicationThread();
addMediaSources(/* index= */ mediaSourceHolderSnapshots.size(), mediaSources); addMediaSources(/* index= */ mediaSourceHolderSnapshots.size(), mediaSources);
} }
@Override
public void addMediaSources(int index, List<MediaSource> mediaSources) { public void addMediaSources(int index, List<MediaSource> mediaSources) {
verifyApplicationThread(); verifyApplicationThread();
Assertions.checkArgument(index >= 0); Assertions.checkArgument(index >= 0);
...@@ -674,6 +648,7 @@ import java.util.concurrent.TimeoutException; ...@@ -674,6 +648,7 @@ import java.util.concurrent.TimeoutException;
/* ignored */ C.INDEX_UNSET); /* ignored */ C.INDEX_UNSET);
} }
@Override
public void removeMediaItems(int fromIndex, int toIndex) { public void removeMediaItems(int fromIndex, int toIndex) {
verifyApplicationThread(); verifyApplicationThread();
toIndex = min(toIndex, mediaSourceHolderSnapshots.size()); toIndex = min(toIndex, mediaSourceHolderSnapshots.size());
...@@ -691,6 +666,7 @@ import java.util.concurrent.TimeoutException; ...@@ -691,6 +666,7 @@ import java.util.concurrent.TimeoutException;
/* ignored */ C.INDEX_UNSET); /* ignored */ C.INDEX_UNSET);
} }
@Override
public void moveMediaItems(int fromIndex, int toIndex, int newFromIndex) { public void moveMediaItems(int fromIndex, int toIndex, int newFromIndex) {
verifyApplicationThread(); verifyApplicationThread();
Assertions.checkArgument( Assertions.checkArgument(
...@@ -720,6 +696,7 @@ import java.util.concurrent.TimeoutException; ...@@ -720,6 +696,7 @@ import java.util.concurrent.TimeoutException;
/* ignored */ C.INDEX_UNSET); /* ignored */ C.INDEX_UNSET);
} }
@Override
public void setShuffleOrder(ShuffleOrder shuffleOrder) { public void setShuffleOrder(ShuffleOrder shuffleOrder) {
verifyApplicationThread(); verifyApplicationThread();
Timeline timeline = createMaskingTimeline(); Timeline timeline = createMaskingTimeline();
...@@ -743,6 +720,7 @@ import java.util.concurrent.TimeoutException; ...@@ -743,6 +720,7 @@ import java.util.concurrent.TimeoutException;
/* ignored */ C.INDEX_UNSET); /* ignored */ C.INDEX_UNSET);
} }
@Override
public void setPauseAtEndOfMediaItems(boolean pauseAtEndOfMediaItems) { public void setPauseAtEndOfMediaItems(boolean pauseAtEndOfMediaItems) {
verifyApplicationThread(); verifyApplicationThread();
if (this.pauseAtEndOfMediaItems == pauseAtEndOfMediaItems) { if (this.pauseAtEndOfMediaItems == pauseAtEndOfMediaItems) {
...@@ -752,11 +730,13 @@ import java.util.concurrent.TimeoutException; ...@@ -752,11 +730,13 @@ import java.util.concurrent.TimeoutException;
internalPlayer.setPauseAtEndOfWindow(pauseAtEndOfMediaItems); internalPlayer.setPauseAtEndOfWindow(pauseAtEndOfMediaItems);
} }
@Override
public boolean getPauseAtEndOfMediaItems() { public boolean getPauseAtEndOfMediaItems() {
verifyApplicationThread(); verifyApplicationThread();
return pauseAtEndOfMediaItems; return pauseAtEndOfMediaItems;
} }
@Override
public void setPlayWhenReady(boolean playWhenReady) { public void setPlayWhenReady(boolean playWhenReady) {
verifyApplicationThread(); verifyApplicationThread();
@AudioFocusManager.PlayerCommand @AudioFocusManager.PlayerCommand
...@@ -765,11 +745,13 @@ import java.util.concurrent.TimeoutException; ...@@ -765,11 +745,13 @@ import java.util.concurrent.TimeoutException;
playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playWhenReady, playerCommand)); playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playWhenReady, playerCommand));
} }
@Override
public boolean getPlayWhenReady() { public boolean getPlayWhenReady() {
verifyApplicationThread(); verifyApplicationThread();
return playbackInfo.playWhenReady; return playbackInfo.playWhenReady;
} }
@Override
public void setRepeatMode(@RepeatMode int repeatMode) { public void setRepeatMode(@RepeatMode int repeatMode) {
verifyApplicationThread(); verifyApplicationThread();
if (this.repeatMode != repeatMode) { if (this.repeatMode != repeatMode) {
...@@ -782,11 +764,13 @@ import java.util.concurrent.TimeoutException; ...@@ -782,11 +764,13 @@ import java.util.concurrent.TimeoutException;
} }
} }
@Override
public @RepeatMode int getRepeatMode() { public @RepeatMode int getRepeatMode() {
verifyApplicationThread(); verifyApplicationThread();
return repeatMode; return repeatMode;
} }
@Override
public void setShuffleModeEnabled(boolean shuffleModeEnabled) { public void setShuffleModeEnabled(boolean shuffleModeEnabled) {
verifyApplicationThread(); verifyApplicationThread();
if (this.shuffleModeEnabled != shuffleModeEnabled) { if (this.shuffleModeEnabled != shuffleModeEnabled) {
...@@ -800,16 +784,19 @@ import java.util.concurrent.TimeoutException; ...@@ -800,16 +784,19 @@ import java.util.concurrent.TimeoutException;
} }
} }
@Override
public boolean getShuffleModeEnabled() { public boolean getShuffleModeEnabled() {
verifyApplicationThread(); verifyApplicationThread();
return shuffleModeEnabled; return shuffleModeEnabled;
} }
@Override
public boolean isLoading() { public boolean isLoading() {
verifyApplicationThread(); verifyApplicationThread();
return playbackInfo.isLoading; return playbackInfo.isLoading;
} }
@Override
public void seekTo(int mediaItemIndex, long positionMs) { public void seekTo(int mediaItemIndex, long positionMs) {
verifyApplicationThread(); verifyApplicationThread();
analyticsCollector.notifySeekStarted(); analyticsCollector.notifySeekStarted();
...@@ -852,21 +839,25 @@ import java.util.concurrent.TimeoutException; ...@@ -852,21 +839,25 @@ import java.util.concurrent.TimeoutException;
oldMaskingMediaItemIndex); oldMaskingMediaItemIndex);
} }
@Override
public long getSeekBackIncrement() { public long getSeekBackIncrement() {
verifyApplicationThread(); verifyApplicationThread();
return seekBackIncrementMs; return seekBackIncrementMs;
} }
@Override
public long getSeekForwardIncrement() { public long getSeekForwardIncrement() {
verifyApplicationThread(); verifyApplicationThread();
return seekForwardIncrementMs; return seekForwardIncrementMs;
} }
@Override
public long getMaxSeekToPreviousPosition() { public long getMaxSeekToPreviousPosition() {
verifyApplicationThread(); verifyApplicationThread();
return C.DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION_MS; return C.DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION_MS;
} }
@Override
public void setPlaybackParameters(PlaybackParameters playbackParameters) { public void setPlaybackParameters(PlaybackParameters playbackParameters) {
verifyApplicationThread(); verifyApplicationThread();
if (playbackParameters == null) { if (playbackParameters == null) {
...@@ -889,11 +880,13 @@ import java.util.concurrent.TimeoutException; ...@@ -889,11 +880,13 @@ import java.util.concurrent.TimeoutException;
/* ignored */ C.INDEX_UNSET); /* ignored */ C.INDEX_UNSET);
} }
@Override
public PlaybackParameters getPlaybackParameters() { public PlaybackParameters getPlaybackParameters() {
verifyApplicationThread(); verifyApplicationThread();
return playbackInfo.playbackParameters; return playbackInfo.playbackParameters;
} }
@Override
public void setSeekParameters(@Nullable SeekParameters seekParameters) { public void setSeekParameters(@Nullable SeekParameters seekParameters) {
verifyApplicationThread(); verifyApplicationThread();
if (seekParameters == null) { if (seekParameters == null) {
...@@ -905,18 +898,20 @@ import java.util.concurrent.TimeoutException; ...@@ -905,18 +898,20 @@ import java.util.concurrent.TimeoutException;
} }
} }
@Override
public SeekParameters getSeekParameters() { public SeekParameters getSeekParameters() {
verifyApplicationThread(); verifyApplicationThread();
return seekParameters; return seekParameters;
} }
@Override
public void setForegroundMode(boolean foregroundMode) { public void setForegroundMode(boolean foregroundMode) {
verifyApplicationThread(); verifyApplicationThread();
if (this.foregroundMode != foregroundMode) { if (this.foregroundMode != foregroundMode) {
this.foregroundMode = foregroundMode; this.foregroundMode = foregroundMode;
if (!internalPlayer.setForegroundMode(foregroundMode)) { if (!internalPlayer.setForegroundMode(foregroundMode)) {
// One of the renderers timed out releasing its resources. // One of the renderers timed out releasing its resources.
stop( stopInternal(
/* reset= */ false, /* reset= */ false,
ExoPlaybackException.createForUnexpected( ExoPlaybackException.createForUnexpected(
new ExoTimeoutException(ExoTimeoutException.TIMEOUT_OPERATION_SET_FOREGROUND_MODE), new ExoTimeoutException(ExoTimeoutException.TIMEOUT_OPERATION_SET_FOREGROUND_MODE),
...@@ -925,55 +920,20 @@ import java.util.concurrent.TimeoutException; ...@@ -925,55 +920,20 @@ import java.util.concurrent.TimeoutException;
} }
} }
@Override
public void stop() { public void stop() {
stop(/* reset= */ false); stop(/* reset= */ false);
} }
@Override
public void stop(boolean reset) { public void stop(boolean reset) {
verifyApplicationThread(); verifyApplicationThread();
audioFocusManager.updateAudioFocus(getPlayWhenReady(), Player.STATE_IDLE); audioFocusManager.updateAudioFocus(getPlayWhenReady(), Player.STATE_IDLE);
stop(reset, /* error= */ null); stopInternal(reset, /* error= */ null);
currentCues = ImmutableList.of(); currentCues = ImmutableList.of();
} }
/** @Override
* Stops the player.
*
* @param reset Whether the playlist should be cleared and whether the playback position and
* playback error should be reset.
* @param error An optional {@link ExoPlaybackException} to set.
*/
public void stop(boolean reset, @Nullable ExoPlaybackException error) {
PlaybackInfo playbackInfo;
if (reset) {
playbackInfo =
removeMediaItemsInternal(
/* fromIndex= */ 0, /* toIndex= */ mediaSourceHolderSnapshots.size());
playbackInfo = playbackInfo.copyWithPlaybackError(null);
} else {
playbackInfo = this.playbackInfo.copyWithLoadingMediaPeriodId(this.playbackInfo.periodId);
playbackInfo.bufferedPositionUs = playbackInfo.positionUs;
playbackInfo.totalBufferedDurationUs = 0;
}
playbackInfo = playbackInfo.copyWithPlaybackState(Player.STATE_IDLE);
if (error != null) {
playbackInfo = playbackInfo.copyWithPlaybackError(error);
}
pendingOperationAcks++;
internalPlayer.stop();
boolean positionDiscontinuity =
playbackInfo.timeline.isEmpty() && !this.playbackInfo.timeline.isEmpty();
updatePlaybackInfo(
playbackInfo,
TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
/* seekProcessed= */ false,
positionDiscontinuity,
DISCONTINUITY_REASON_REMOVE,
/* discontinuityWindowStartPositionUs= */ getCurrentPositionUsInternal(playbackInfo),
/* ignored */ C.INDEX_UNSET);
}
public void release() { public void release() {
Log.i( Log.i(
TAG, TAG,
...@@ -1027,11 +987,13 @@ import java.util.concurrent.TimeoutException; ...@@ -1027,11 +987,13 @@ import java.util.concurrent.TimeoutException;
playerReleased = true; playerReleased = true;
} }
@Override
public PlayerMessage createMessage(Target target) { public PlayerMessage createMessage(Target target) {
verifyApplicationThread(); verifyApplicationThread();
return createMessageInternal(target); return createMessageInternal(target);
} }
@Override
public int getCurrentPeriodIndex() { public int getCurrentPeriodIndex() {
verifyApplicationThread(); verifyApplicationThread();
if (playbackInfo.timeline.isEmpty()) { if (playbackInfo.timeline.isEmpty()) {
...@@ -1041,12 +1003,14 @@ import java.util.concurrent.TimeoutException; ...@@ -1041,12 +1003,14 @@ import java.util.concurrent.TimeoutException;
} }
} }
@Override
public int getCurrentMediaItemIndex() { public int getCurrentMediaItemIndex() {
verifyApplicationThread(); verifyApplicationThread();
int currentWindowIndex = getCurrentWindowIndexInternal(); int currentWindowIndex = getCurrentWindowIndexInternal();
return currentWindowIndex == C.INDEX_UNSET ? 0 : currentWindowIndex; return currentWindowIndex == C.INDEX_UNSET ? 0 : currentWindowIndex;
} }
@Override
public long getDuration() { public long getDuration() {
verifyApplicationThread(); verifyApplicationThread();
if (isPlayingAd()) { if (isPlayingAd()) {
...@@ -1058,18 +1022,13 @@ import java.util.concurrent.TimeoutException; ...@@ -1058,18 +1022,13 @@ import java.util.concurrent.TimeoutException;
return getContentDuration(); return getContentDuration();
} }
private long getContentDuration() { @Override
Timeline timeline = getCurrentTimeline();
return timeline.isEmpty()
? C.TIME_UNSET
: timeline.getWindow(getCurrentMediaItemIndex(), window).getDurationMs();
}
public long getCurrentPosition() { public long getCurrentPosition() {
verifyApplicationThread(); verifyApplicationThread();
return Util.usToMs(getCurrentPositionUsInternal(playbackInfo)); return Util.usToMs(getCurrentPositionUsInternal(playbackInfo));
} }
@Override
public long getBufferedPosition() { public long getBufferedPosition() {
verifyApplicationThread(); verifyApplicationThread();
if (isPlayingAd()) { if (isPlayingAd()) {
...@@ -1080,26 +1039,31 @@ import java.util.concurrent.TimeoutException; ...@@ -1080,26 +1039,31 @@ import java.util.concurrent.TimeoutException;
return getContentBufferedPosition(); return getContentBufferedPosition();
} }
@Override
public long getTotalBufferedDuration() { public long getTotalBufferedDuration() {
verifyApplicationThread(); verifyApplicationThread();
return Util.usToMs(playbackInfo.totalBufferedDurationUs); return Util.usToMs(playbackInfo.totalBufferedDurationUs);
} }
@Override
public boolean isPlayingAd() { public boolean isPlayingAd() {
verifyApplicationThread(); verifyApplicationThread();
return playbackInfo.periodId.isAd(); return playbackInfo.periodId.isAd();
} }
@Override
public int getCurrentAdGroupIndex() { public int getCurrentAdGroupIndex() {
verifyApplicationThread(); verifyApplicationThread();
return isPlayingAd() ? playbackInfo.periodId.adGroupIndex : C.INDEX_UNSET; return isPlayingAd() ? playbackInfo.periodId.adGroupIndex : C.INDEX_UNSET;
} }
@Override
public int getCurrentAdIndexInAdGroup() { public int getCurrentAdIndexInAdGroup() {
verifyApplicationThread(); verifyApplicationThread();
return isPlayingAd() ? playbackInfo.periodId.adIndexInAdGroup : C.INDEX_UNSET; return isPlayingAd() ? playbackInfo.periodId.adIndexInAdGroup : C.INDEX_UNSET;
} }
@Override
public long getContentPosition() { public long getContentPosition() {
verifyApplicationThread(); verifyApplicationThread();
if (isPlayingAd()) { if (isPlayingAd()) {
...@@ -1115,6 +1079,7 @@ import java.util.concurrent.TimeoutException; ...@@ -1115,6 +1079,7 @@ import java.util.concurrent.TimeoutException;
} }
} }
@Override
public long getContentBufferedPosition() { public long getContentBufferedPosition() {
verifyApplicationThread(); verifyApplicationThread();
if (playbackInfo.timeline.isEmpty()) { if (playbackInfo.timeline.isEmpty()) {
...@@ -1139,46 +1104,55 @@ import java.util.concurrent.TimeoutException; ...@@ -1139,46 +1104,55 @@ import java.util.concurrent.TimeoutException;
playbackInfo.timeline, playbackInfo.loadingMediaPeriodId, contentBufferedPositionUs)); playbackInfo.timeline, playbackInfo.loadingMediaPeriodId, contentBufferedPositionUs));
} }
@Override
public int getRendererCount() { public int getRendererCount() {
verifyApplicationThread(); verifyApplicationThread();
return renderers.length; return renderers.length;
} }
@Override
public @C.TrackType int getRendererType(int index) { public @C.TrackType int getRendererType(int index) {
verifyApplicationThread(); verifyApplicationThread();
return renderers[index].getTrackType(); return renderers[index].getTrackType();
} }
@Override
public Renderer getRenderer(int index) { public Renderer getRenderer(int index) {
verifyApplicationThread(); verifyApplicationThread();
return renderers[index]; return renderers[index];
} }
@Override
public TrackSelector getTrackSelector() { public TrackSelector getTrackSelector() {
verifyApplicationThread(); verifyApplicationThread();
return trackSelector; return trackSelector;
} }
@Override
public TrackGroupArray getCurrentTrackGroups() { public TrackGroupArray getCurrentTrackGroups() {
verifyApplicationThread(); verifyApplicationThread();
return playbackInfo.trackGroups; return playbackInfo.trackGroups;
} }
@Override
public TrackSelectionArray getCurrentTrackSelections() { public TrackSelectionArray getCurrentTrackSelections() {
verifyApplicationThread(); verifyApplicationThread();
return new TrackSelectionArray(playbackInfo.trackSelectorResult.selections); return new TrackSelectionArray(playbackInfo.trackSelectorResult.selections);
} }
@Override
public TracksInfo getCurrentTracksInfo() { public TracksInfo getCurrentTracksInfo() {
verifyApplicationThread(); verifyApplicationThread();
return playbackInfo.trackSelectorResult.tracksInfo; return playbackInfo.trackSelectorResult.tracksInfo;
} }
@Override
public TrackSelectionParameters getTrackSelectionParameters() { public TrackSelectionParameters getTrackSelectionParameters() {
verifyApplicationThread(); verifyApplicationThread();
return trackSelector.getParameters(); return trackSelector.getParameters();
} }
@Override
public void setTrackSelectionParameters(TrackSelectionParameters parameters) { public void setTrackSelectionParameters(TrackSelectionParameters parameters) {
verifyApplicationThread(); verifyApplicationThread();
if (!trackSelector.isSetParametersSupported() if (!trackSelector.isSetParametersSupported()
...@@ -1191,16 +1165,19 @@ import java.util.concurrent.TimeoutException; ...@@ -1191,16 +1165,19 @@ import java.util.concurrent.TimeoutException;
listener -> listener.onTrackSelectionParametersChanged(parameters)); listener -> listener.onTrackSelectionParametersChanged(parameters));
} }
@Override
public MediaMetadata getMediaMetadata() { public MediaMetadata getMediaMetadata() {
verifyApplicationThread(); verifyApplicationThread();
return mediaMetadata; return mediaMetadata;
} }
@Override
public MediaMetadata getPlaylistMetadata() { public MediaMetadata getPlaylistMetadata() {
verifyApplicationThread(); verifyApplicationThread();
return playlistMetadata; return playlistMetadata;
} }
@Override
public void setPlaylistMetadata(MediaMetadata playlistMetadata) { public void setPlaylistMetadata(MediaMetadata playlistMetadata) {
verifyApplicationThread(); verifyApplicationThread();
checkNotNull(playlistMetadata); checkNotNull(playlistMetadata);
...@@ -1213,21 +1190,25 @@ import java.util.concurrent.TimeoutException; ...@@ -1213,21 +1190,25 @@ import java.util.concurrent.TimeoutException;
listener -> listener.onPlaylistMetadataChanged(this.playlistMetadata)); listener -> listener.onPlaylistMetadataChanged(this.playlistMetadata));
} }
@Override
public Timeline getCurrentTimeline() { public Timeline getCurrentTimeline() {
verifyApplicationThread(); verifyApplicationThread();
return playbackInfo.timeline; return playbackInfo.timeline;
} }
@Override
public void setVideoScalingMode(@C.VideoScalingMode int videoScalingMode) { public void setVideoScalingMode(@C.VideoScalingMode int videoScalingMode) {
verifyApplicationThread(); verifyApplicationThread();
this.videoScalingMode = videoScalingMode; this.videoScalingMode = videoScalingMode;
sendRendererMessage(TRACK_TYPE_VIDEO, MSG_SET_SCALING_MODE, videoScalingMode); sendRendererMessage(TRACK_TYPE_VIDEO, MSG_SET_SCALING_MODE, videoScalingMode);
} }
@Override
public @C.VideoScalingMode int getVideoScalingMode() { public @C.VideoScalingMode int getVideoScalingMode() {
return videoScalingMode; return videoScalingMode;
} }
@Override
public void setVideoChangeFrameRateStrategy( public void setVideoChangeFrameRateStrategy(
@C.VideoChangeFrameRateStrategy int videoChangeFrameRateStrategy) { @C.VideoChangeFrameRateStrategy int videoChangeFrameRateStrategy) {
verifyApplicationThread(); verifyApplicationThread();
...@@ -1239,14 +1220,17 @@ import java.util.concurrent.TimeoutException; ...@@ -1239,14 +1220,17 @@ import java.util.concurrent.TimeoutException;
TRACK_TYPE_VIDEO, MSG_SET_CHANGE_FRAME_RATE_STRATEGY, videoChangeFrameRateStrategy); TRACK_TYPE_VIDEO, MSG_SET_CHANGE_FRAME_RATE_STRATEGY, videoChangeFrameRateStrategy);
} }
@Override
public @C.VideoChangeFrameRateStrategy int getVideoChangeFrameRateStrategy() { public @C.VideoChangeFrameRateStrategy int getVideoChangeFrameRateStrategy() {
return videoChangeFrameRateStrategy; return videoChangeFrameRateStrategy;
} }
@Override
public VideoSize getVideoSize() { public VideoSize getVideoSize() {
return videoSize; return videoSize;
} }
@Override
public void clearVideoSurface() { public void clearVideoSurface() {
verifyApplicationThread(); verifyApplicationThread();
removeSurfaceCallbacks(); removeSurfaceCallbacks();
...@@ -1254,6 +1238,7 @@ import java.util.concurrent.TimeoutException; ...@@ -1254,6 +1238,7 @@ import java.util.concurrent.TimeoutException;
maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0); maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0);
} }
@Override
public void clearVideoSurface(@Nullable Surface surface) { public void clearVideoSurface(@Nullable Surface surface) {
verifyApplicationThread(); verifyApplicationThread();
if (surface != null && surface == videoOutput) { if (surface != null && surface == videoOutput) {
...@@ -1261,6 +1246,7 @@ import java.util.concurrent.TimeoutException; ...@@ -1261,6 +1246,7 @@ import java.util.concurrent.TimeoutException;
} }
} }
@Override
public void setVideoSurface(@Nullable Surface surface) { public void setVideoSurface(@Nullable Surface surface) {
verifyApplicationThread(); verifyApplicationThread();
removeSurfaceCallbacks(); removeSurfaceCallbacks();
...@@ -1269,6 +1255,7 @@ import java.util.concurrent.TimeoutException; ...@@ -1269,6 +1255,7 @@ import java.util.concurrent.TimeoutException;
maybeNotifySurfaceSizeChanged(/* width= */ newSurfaceSize, /* height= */ newSurfaceSize); maybeNotifySurfaceSizeChanged(/* width= */ newSurfaceSize, /* height= */ newSurfaceSize);
} }
@Override
public void setVideoSurfaceHolder(@Nullable SurfaceHolder surfaceHolder) { public void setVideoSurfaceHolder(@Nullable SurfaceHolder surfaceHolder) {
verifyApplicationThread(); verifyApplicationThread();
if (surfaceHolder == null) { if (surfaceHolder == null) {
...@@ -1290,6 +1277,7 @@ import java.util.concurrent.TimeoutException; ...@@ -1290,6 +1277,7 @@ import java.util.concurrent.TimeoutException;
} }
} }
@Override
public void clearVideoSurfaceHolder(@Nullable SurfaceHolder surfaceHolder) { public void clearVideoSurfaceHolder(@Nullable SurfaceHolder surfaceHolder) {
verifyApplicationThread(); verifyApplicationThread();
if (surfaceHolder != null && surfaceHolder == this.surfaceHolder) { if (surfaceHolder != null && surfaceHolder == this.surfaceHolder) {
...@@ -1297,6 +1285,7 @@ import java.util.concurrent.TimeoutException; ...@@ -1297,6 +1285,7 @@ import java.util.concurrent.TimeoutException;
} }
} }
@Override
public void setVideoSurfaceView(@Nullable SurfaceView surfaceView) { public void setVideoSurfaceView(@Nullable SurfaceView surfaceView) {
verifyApplicationThread(); verifyApplicationThread();
if (surfaceView instanceof VideoDecoderOutputBufferRenderer) { if (surfaceView instanceof VideoDecoderOutputBufferRenderer) {
...@@ -1318,11 +1307,13 @@ import java.util.concurrent.TimeoutException; ...@@ -1318,11 +1307,13 @@ import java.util.concurrent.TimeoutException;
} }
} }
@Override
public void clearVideoSurfaceView(@Nullable SurfaceView surfaceView) { public void clearVideoSurfaceView(@Nullable SurfaceView surfaceView) {
verifyApplicationThread(); verifyApplicationThread();
clearVideoSurfaceHolder(surfaceView == null ? null : surfaceView.getHolder()); clearVideoSurfaceHolder(surfaceView == null ? null : surfaceView.getHolder());
} }
@Override
public void setVideoTextureView(@Nullable TextureView textureView) { public void setVideoTextureView(@Nullable TextureView textureView) {
verifyApplicationThread(); verifyApplicationThread();
if (textureView == null) { if (textureView == null) {
...@@ -1347,6 +1338,7 @@ import java.util.concurrent.TimeoutException; ...@@ -1347,6 +1338,7 @@ import java.util.concurrent.TimeoutException;
} }
} }
@Override
public void clearVideoTextureView(@Nullable TextureView textureView) { public void clearVideoTextureView(@Nullable TextureView textureView) {
verifyApplicationThread(); verifyApplicationThread();
if (textureView != null && textureView == this.textureView) { if (textureView != null && textureView == this.textureView) {
...@@ -1354,6 +1346,7 @@ import java.util.concurrent.TimeoutException; ...@@ -1354,6 +1346,7 @@ import java.util.concurrent.TimeoutException;
} }
} }
@Override
public void setAudioAttributes(AudioAttributes newAudioAttributes, boolean handleAudioFocus) { public void setAudioAttributes(AudioAttributes newAudioAttributes, boolean handleAudioFocus) {
verifyApplicationThread(); verifyApplicationThread();
if (playerReleased) { if (playerReleased) {
...@@ -1378,10 +1371,12 @@ import java.util.concurrent.TimeoutException; ...@@ -1378,10 +1371,12 @@ import java.util.concurrent.TimeoutException;
listeners.flushEvents(); listeners.flushEvents();
} }
@Override
public AudioAttributes getAudioAttributes() { public AudioAttributes getAudioAttributes() {
return audioAttributes; return audioAttributes;
} }
@Override
public void setAudioSessionId(int audioSessionId) { public void setAudioSessionId(int audioSessionId) {
verifyApplicationThread(); verifyApplicationThread();
if (this.audioSessionId == audioSessionId) { if (this.audioSessionId == audioSessionId) {
...@@ -1406,19 +1401,23 @@ import java.util.concurrent.TimeoutException; ...@@ -1406,19 +1401,23 @@ import java.util.concurrent.TimeoutException;
EVENT_AUDIO_SESSION_ID, listener -> listener.onAudioSessionIdChanged(finalAudioSessionId)); EVENT_AUDIO_SESSION_ID, listener -> listener.onAudioSessionIdChanged(finalAudioSessionId));
} }
@Override
public int getAudioSessionId() { public int getAudioSessionId() {
return audioSessionId; return audioSessionId;
} }
@Override
public void setAuxEffectInfo(AuxEffectInfo auxEffectInfo) { public void setAuxEffectInfo(AuxEffectInfo auxEffectInfo) {
verifyApplicationThread(); verifyApplicationThread();
sendRendererMessage(TRACK_TYPE_AUDIO, MSG_SET_AUX_EFFECT_INFO, auxEffectInfo); sendRendererMessage(TRACK_TYPE_AUDIO, MSG_SET_AUX_EFFECT_INFO, auxEffectInfo);
} }
@Override
public void clearAuxEffectInfo() { public void clearAuxEffectInfo() {
setAuxEffectInfo(new AuxEffectInfo(AuxEffectInfo.NO_AUX_EFFECT_ID, /* sendLevel= */ 0f)); setAuxEffectInfo(new AuxEffectInfo(AuxEffectInfo.NO_AUX_EFFECT_ID, /* sendLevel= */ 0f));
} }
@Override
public void setVolume(float volume) { public void setVolume(float volume) {
verifyApplicationThread(); verifyApplicationThread();
volume = Util.constrainValue(volume, /* min= */ 0, /* max= */ 1); volume = Util.constrainValue(volume, /* min= */ 0, /* max= */ 1);
...@@ -1431,14 +1430,17 @@ import java.util.concurrent.TimeoutException; ...@@ -1431,14 +1430,17 @@ import java.util.concurrent.TimeoutException;
listeners.sendEvent(EVENT_VOLUME_CHANGED, listener -> listener.onVolumeChanged(finalVolume)); listeners.sendEvent(EVENT_VOLUME_CHANGED, listener -> listener.onVolumeChanged(finalVolume));
} }
@Override
public float getVolume() { public float getVolume() {
return volume; return volume;
} }
@Override
public boolean getSkipSilenceEnabled() { public boolean getSkipSilenceEnabled() {
return skipSilenceEnabled; return skipSilenceEnabled;
} }
@Override
public void setSkipSilenceEnabled(boolean newSkipSilenceEnabled) { public void setSkipSilenceEnabled(boolean newSkipSilenceEnabled) {
verifyApplicationThread(); verifyApplicationThread();
if (skipSilenceEnabled == newSkipSilenceEnabled) { if (skipSilenceEnabled == newSkipSilenceEnabled) {
...@@ -1451,21 +1453,25 @@ import java.util.concurrent.TimeoutException; ...@@ -1451,21 +1453,25 @@ import java.util.concurrent.TimeoutException;
listener -> listener.onSkipSilenceEnabledChanged(newSkipSilenceEnabled)); listener -> listener.onSkipSilenceEnabledChanged(newSkipSilenceEnabled));
} }
@Override
public AnalyticsCollector getAnalyticsCollector() { public AnalyticsCollector getAnalyticsCollector() {
return analyticsCollector; return analyticsCollector;
} }
@Override
public void addAnalyticsListener(AnalyticsListener listener) { public void addAnalyticsListener(AnalyticsListener listener) {
// Don't verify application thread. We allow calls to this method from any thread. // Don't verify application thread. We allow calls to this method from any thread.
checkNotNull(listener); checkNotNull(listener);
analyticsCollector.addListener(listener); analyticsCollector.addListener(listener);
} }
@Override
public void removeAnalyticsListener(AnalyticsListener listener) { public void removeAnalyticsListener(AnalyticsListener listener) {
// Don't verify application thread. We allow calls to this method from any thread. // Don't verify application thread. We allow calls to this method from any thread.
analyticsCollector.removeListener(listener); analyticsCollector.removeListener(listener);
} }
@Override
public void setHandleAudioBecomingNoisy(boolean handleAudioBecomingNoisy) { public void setHandleAudioBecomingNoisy(boolean handleAudioBecomingNoisy) {
verifyApplicationThread(); verifyApplicationThread();
if (playerReleased) { if (playerReleased) {
...@@ -1474,6 +1480,7 @@ import java.util.concurrent.TimeoutException; ...@@ -1474,6 +1480,7 @@ import java.util.concurrent.TimeoutException;
audioBecomingNoisyManager.setEnabled(handleAudioBecomingNoisy); audioBecomingNoisyManager.setEnabled(handleAudioBecomingNoisy);
} }
@Override
public void setPriorityTaskManager(@Nullable PriorityTaskManager priorityTaskManager) { public void setPriorityTaskManager(@Nullable PriorityTaskManager priorityTaskManager) {
verifyApplicationThread(); verifyApplicationThread();
if (Util.areEqual(this.priorityTaskManager, priorityTaskManager)) { if (Util.areEqual(this.priorityTaskManager, priorityTaskManager)) {
...@@ -1491,26 +1498,31 @@ import java.util.concurrent.TimeoutException; ...@@ -1491,26 +1498,31 @@ import java.util.concurrent.TimeoutException;
this.priorityTaskManager = priorityTaskManager; this.priorityTaskManager = priorityTaskManager;
} }
@Override
@Nullable @Nullable
public Format getVideoFormat() { public Format getVideoFormat() {
return videoFormat; return videoFormat;
} }
@Override
@Nullable @Nullable
public Format getAudioFormat() { public Format getAudioFormat() {
return audioFormat; return audioFormat;
} }
@Override
@Nullable @Nullable
public DecoderCounters getVideoDecoderCounters() { public DecoderCounters getVideoDecoderCounters() {
return videoDecoderCounters; return videoDecoderCounters;
} }
@Override
@Nullable @Nullable
public DecoderCounters getAudioDecoderCounters() { public DecoderCounters getAudioDecoderCounters() {
return audioDecoderCounters; return audioDecoderCounters;
} }
@Override
public void setVideoFrameMetadataListener(VideoFrameMetadataListener listener) { public void setVideoFrameMetadataListener(VideoFrameMetadataListener listener) {
verifyApplicationThread(); verifyApplicationThread();
videoFrameMetadataListener = listener; videoFrameMetadataListener = listener;
...@@ -1520,6 +1532,7 @@ import java.util.concurrent.TimeoutException; ...@@ -1520,6 +1532,7 @@ import java.util.concurrent.TimeoutException;
.send(); .send();
} }
@Override
public void clearVideoFrameMetadataListener(VideoFrameMetadataListener listener) { public void clearVideoFrameMetadataListener(VideoFrameMetadataListener listener) {
verifyApplicationThread(); verifyApplicationThread();
if (videoFrameMetadataListener != listener) { if (videoFrameMetadataListener != listener) {
...@@ -1531,6 +1544,7 @@ import java.util.concurrent.TimeoutException; ...@@ -1531,6 +1544,7 @@ import java.util.concurrent.TimeoutException;
.send(); .send();
} }
@Override
public void setCameraMotionListener(CameraMotionListener listener) { public void setCameraMotionListener(CameraMotionListener listener) {
verifyApplicationThread(); verifyApplicationThread();
cameraMotionListener = listener; cameraMotionListener = listener;
...@@ -1540,6 +1554,7 @@ import java.util.concurrent.TimeoutException; ...@@ -1540,6 +1554,7 @@ import java.util.concurrent.TimeoutException;
.send(); .send();
} }
@Override
public void clearCameraMotionListener(CameraMotionListener listener) { public void clearCameraMotionListener(CameraMotionListener listener) {
verifyApplicationThread(); verifyApplicationThread();
if (cameraMotionListener != listener) { if (cameraMotionListener != listener) {
...@@ -1551,27 +1566,32 @@ import java.util.concurrent.TimeoutException; ...@@ -1551,27 +1566,32 @@ import java.util.concurrent.TimeoutException;
.send(); .send();
} }
@Override
public List<Cue> getCurrentCues() { public List<Cue> getCurrentCues() {
verifyApplicationThread(); verifyApplicationThread();
return currentCues; return currentCues;
} }
@Override
public void addListener(Listener listener) { public void addListener(Listener listener) {
// Don't verify application thread. We allow calls to this method from any thread. // Don't verify application thread. We allow calls to this method from any thread.
checkNotNull(listener); checkNotNull(listener);
listeners.add(listener); listeners.add(listener);
} }
@Override
public void removeListener(Listener listener) { public void removeListener(Listener listener) {
// Don't verify application thread. We allow calls to this method from any thread. // Don't verify application thread. We allow calls to this method from any thread.
checkNotNull(listener); checkNotNull(listener);
listeners.remove(listener); listeners.remove(listener);
} }
@Override
public void setHandleWakeLock(boolean handleWakeLock) { public void setHandleWakeLock(boolean handleWakeLock) {
setWakeMode(handleWakeLock ? C.WAKE_MODE_LOCAL : C.WAKE_MODE_NONE); setWakeMode(handleWakeLock ? C.WAKE_MODE_LOCAL : C.WAKE_MODE_NONE);
} }
@Override
public void setWakeMode(@C.WakeMode int wakeMode) { public void setWakeMode(@C.WakeMode int wakeMode) {
verifyApplicationThread(); verifyApplicationThread();
switch (wakeMode) { switch (wakeMode) {
...@@ -1592,36 +1612,43 @@ import java.util.concurrent.TimeoutException; ...@@ -1592,36 +1612,43 @@ import java.util.concurrent.TimeoutException;
} }
} }
@Override
public DeviceInfo getDeviceInfo() { public DeviceInfo getDeviceInfo() {
verifyApplicationThread(); verifyApplicationThread();
return deviceInfo; return deviceInfo;
} }
@Override
public int getDeviceVolume() { public int getDeviceVolume() {
verifyApplicationThread(); verifyApplicationThread();
return streamVolumeManager.getVolume(); return streamVolumeManager.getVolume();
} }
@Override
public boolean isDeviceMuted() { public boolean isDeviceMuted() {
verifyApplicationThread(); verifyApplicationThread();
return streamVolumeManager.isMuted(); return streamVolumeManager.isMuted();
} }
@Override
public void setDeviceVolume(int volume) { public void setDeviceVolume(int volume) {
verifyApplicationThread(); verifyApplicationThread();
streamVolumeManager.setVolume(volume); streamVolumeManager.setVolume(volume);
} }
@Override
public void increaseDeviceVolume() { public void increaseDeviceVolume() {
verifyApplicationThread(); verifyApplicationThread();
streamVolumeManager.increaseVolume(); streamVolumeManager.increaseVolume();
} }
@Override
public void decreaseDeviceVolume() { public void decreaseDeviceVolume() {
verifyApplicationThread(); verifyApplicationThread();
streamVolumeManager.decreaseVolume(); streamVolumeManager.decreaseVolume();
} }
@Override
public void setDeviceMuted(boolean muted) { public void setDeviceMuted(boolean muted) {
verifyApplicationThread(); verifyApplicationThread();
streamVolumeManager.setMuted(muted); streamVolumeManager.setMuted(muted);
...@@ -1631,6 +1658,44 @@ import java.util.concurrent.TimeoutException; ...@@ -1631,6 +1658,44 @@ import java.util.concurrent.TimeoutException;
this.throwsWhenUsingWrongThread = throwsWhenUsingWrongThread; this.throwsWhenUsingWrongThread = throwsWhenUsingWrongThread;
} }
/**
* Stops the player.
*
* @param reset Whether the playlist should be cleared and whether the playback position and
* playback error should be reset.
* @param error An optional {@link ExoPlaybackException} to set.
*/
private void stopInternal(boolean reset, @Nullable ExoPlaybackException error) {
PlaybackInfo playbackInfo;
if (reset) {
playbackInfo =
removeMediaItemsInternal(
/* fromIndex= */ 0, /* toIndex= */ mediaSourceHolderSnapshots.size());
playbackInfo = playbackInfo.copyWithPlaybackError(null);
} else {
playbackInfo = this.playbackInfo.copyWithLoadingMediaPeriodId(this.playbackInfo.periodId);
playbackInfo.bufferedPositionUs = playbackInfo.positionUs;
playbackInfo.totalBufferedDurationUs = 0;
}
playbackInfo = playbackInfo.copyWithPlaybackState(Player.STATE_IDLE);
if (error != null) {
playbackInfo = playbackInfo.copyWithPlaybackError(error);
}
pendingOperationAcks++;
internalPlayer.stop();
boolean positionDiscontinuity =
playbackInfo.timeline.isEmpty() && !this.playbackInfo.timeline.isEmpty();
updatePlaybackInfo(
playbackInfo,
TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
/* seekProcessed= */ false,
positionDiscontinuity,
DISCONTINUITY_REASON_REMOVE,
/* discontinuityWindowStartPositionUs= */ getCurrentPositionUsInternal(playbackInfo),
/* ignored */ C.INDEX_UNSET);
}
private int getCurrentWindowIndexInternal() { private int getCurrentWindowIndexInternal() {
if (playbackInfo.timeline.isEmpty()) { if (playbackInfo.timeline.isEmpty()) {
return maskingWindowIndex; return maskingWindowIndex;
...@@ -2415,7 +2480,7 @@ import java.util.concurrent.TimeoutException; ...@@ -2415,7 +2480,7 @@ import java.util.concurrent.TimeoutException;
} }
this.videoOutput = videoOutput; this.videoOutput = videoOutput;
if (messageDeliveryTimedOut) { if (messageDeliveryTimedOut) {
stop( stopInternal(
/* reset= */ false, /* reset= */ false,
ExoPlaybackException.createForUnexpected( ExoPlaybackException.createForUnexpected(
new ExoTimeoutException(ExoTimeoutException.TIMEOUT_OPERATION_DETACH_SURFACE), new ExoTimeoutException(ExoTimeoutException.TIMEOUT_OPERATION_DETACH_SURFACE),
......
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