Remove ExoPlayerImpl inheritance from BasePlayer.

This inheritance is really confusing because ExoPlayerImpl is not
a full Player interface implementation. It also claims to be an
ExoPlayer implementation in the Javadoc which isn't true in its
current state.

Removing the inheritance also allows to clean up some unused methods.

PiperOrigin-RevId: 411756963
This commit is contained in:
tonihei 2021-11-23 10:25:22 +00:00
parent 6adf41f03a
commit 736ea9a148
5 changed files with 128 additions and 236 deletions

View File

@ -1094,7 +1094,7 @@ public final class CastPlayer extends BasePlayer {
private void updateAvailableCommandsAndNotifyIfChanged() { private void updateAvailableCommandsAndNotifyIfChanged() {
Commands previousAvailableCommands = availableCommands; Commands previousAvailableCommands = availableCommands;
availableCommands = getAvailableCommands(PERMANENT_AVAILABLE_COMMANDS); availableCommands = Util.getAvailableCommands(/* player= */ this, PERMANENT_AVAILABLE_COMMANDS);
if (!availableCommands.equals(previousAvailableCommands)) { if (!availableCommands.equals(previousAvailableCommands)) {
listeners.queueEvent( listeners.queueEvent(
Player.EVENT_AVAILABLE_COMMANDS_CHANGED, Player.EVENT_AVAILABLE_COMMANDS_CHANGED,

View File

@ -384,37 +384,6 @@ public abstract class BasePlayer implements Player {
: timeline.getWindow(getCurrentMediaItemIndex(), window).getDurationMs(); : timeline.getWindow(getCurrentMediaItemIndex(), window).getDurationMs();
} }
/**
* Returns the {@link Commands} available in the player.
*
* @param permanentAvailableCommands The commands permanently available in the player.
* @return The available {@link Commands}.
*/
protected Commands getAvailableCommands(Commands permanentAvailableCommands) {
return new Commands.Builder()
.addAll(permanentAvailableCommands)
.addIf(COMMAND_SEEK_TO_DEFAULT_POSITION, !isPlayingAd())
.addIf(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, isCurrentMediaItemSeekable() && !isPlayingAd())
.addIf(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM, hasPreviousMediaItem() && !isPlayingAd())
.addIf(
COMMAND_SEEK_TO_PREVIOUS,
!getCurrentTimeline().isEmpty()
&& (hasPreviousMediaItem()
|| !isCurrentMediaItemLive()
|| isCurrentMediaItemSeekable())
&& !isPlayingAd())
.addIf(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, hasNextMediaItem() && !isPlayingAd())
.addIf(
COMMAND_SEEK_TO_NEXT,
!getCurrentTimeline().isEmpty()
&& (hasNextMediaItem() || (isCurrentMediaItemLive() && isCurrentMediaItemDynamic()))
&& !isPlayingAd())
.addIf(COMMAND_SEEK_TO_MEDIA_ITEM, !isPlayingAd())
.addIf(COMMAND_SEEK_BACK, isCurrentMediaItemSeekable() && !isPlayingAd())
.addIf(COMMAND_SEEK_FORWARD, isCurrentMediaItemSeekable() && !isPlayingAd())
.build();
}
@RepeatMode @RepeatMode
private int getRepeatModeForNavigation() { private int getRepeatModeForNavigation() {
@RepeatMode int repeatMode = getRepeatMode(); @RepeatMode int repeatMode = getRepeatMode();

View File

@ -16,6 +16,15 @@
package androidx.media3.common.util; package androidx.media3.common.util;
import static android.content.Context.UI_MODE_SERVICE; import static android.content.Context.UI_MODE_SERVICE;
import static androidx.media3.common.Player.COMMAND_SEEK_BACK;
import static androidx.media3.common.Player.COMMAND_SEEK_FORWARD;
import static androidx.media3.common.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM;
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_SEEK_TO_NEXT;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static java.lang.Math.abs; import static java.lang.Math.abs;
import static java.lang.Math.max; import static java.lang.Math.max;
@ -64,6 +73,8 @@ import androidx.media3.common.MediaLibraryInfo;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.ParserException; import androidx.media3.common.ParserException;
import androidx.media3.common.PlaybackException; import androidx.media3.common.PlaybackException;
import androidx.media3.common.Player;
import androidx.media3.common.Player.Commands;
import com.google.common.base.Ascii; import com.google.common.base.Ascii;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -2479,6 +2490,43 @@ public final class Util {
} }
} }
/**
* Returns the {@link Commands} available in the {@link Player}.
*
* @param player The {@link Player}.
* @param permanentAvailableCommands The commands permanently available in the player.
* @return The available {@link Commands}.
*/
public static Commands getAvailableCommands(Player player, Commands permanentAvailableCommands) {
boolean isPlayingAd = player.isPlayingAd();
boolean isCurrentMediaItemSeekable = player.isCurrentMediaItemSeekable();
boolean hasPreviousMediaItem = player.hasPreviousMediaItem();
boolean hasNextMediaItem = player.hasNextMediaItem();
boolean isCurrentMediaItemLive = player.isCurrentMediaItemLive();
boolean isCurrentMediaItemDynamic = player.isCurrentMediaItemDynamic();
boolean isTimelineEmpty = player.getCurrentTimeline().isEmpty();
return new Commands.Builder()
.addAll(permanentAvailableCommands)
.addIf(COMMAND_SEEK_TO_DEFAULT_POSITION, !isPlayingAd)
.addIf(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, isCurrentMediaItemSeekable && !isPlayingAd)
.addIf(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM, hasPreviousMediaItem && !isPlayingAd)
.addIf(
COMMAND_SEEK_TO_PREVIOUS,
!isTimelineEmpty
&& (hasPreviousMediaItem || !isCurrentMediaItemLive || isCurrentMediaItemSeekable)
&& !isPlayingAd)
.addIf(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, hasNextMediaItem && !isPlayingAd)
.addIf(
COMMAND_SEEK_TO_NEXT,
!isTimelineEmpty
&& (hasNextMediaItem || (isCurrentMediaItemLive && isCurrentMediaItemDynamic))
&& !isPlayingAd)
.addIf(COMMAND_SEEK_TO_MEDIA_ITEM, !isPlayingAd)
.addIf(COMMAND_SEEK_BACK, isCurrentMediaItemSeekable && !isPlayingAd)
.addIf(COMMAND_SEEK_FORWARD, isCurrentMediaItemSeekable && !isPlayingAd)
.build();
}
@Nullable @Nullable
private static String getSystemProperty(String name) { private static String getSystemProperty(String name) {
try { try {

View File

@ -15,6 +15,39 @@
*/ */
package androidx.media3.exoplayer; package androidx.media3.exoplayer;
import static androidx.media3.common.Player.COMMAND_CHANGE_MEDIA_ITEMS;
import static androidx.media3.common.Player.COMMAND_GET_CURRENT_MEDIA_ITEM;
import static androidx.media3.common.Player.COMMAND_GET_MEDIA_ITEMS_METADATA;
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_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_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_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_MEDIA_METADATA_CHANGED;
import static androidx.media3.common.Player.EVENT_PLAYLIST_METADATA_CHANGED;
import static androidx.media3.common.Player.EVENT_TRACK_SELECTION_PARAMETERS_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_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;
@ -26,17 +59,10 @@ import android.media.metrics.LogSessionId;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.Pair; import android.util.Pair;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;
import androidx.annotation.DoNotInline; import androidx.annotation.DoNotInline;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.media3.common.AudioAttributes;
import androidx.media3.common.BasePlayer;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.DeviceInfo;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.IllegalSeekPositionException; import androidx.media3.common.IllegalSeekPositionException;
import androidx.media3.common.MediaItem; import androidx.media3.common.MediaItem;
@ -46,14 +72,23 @@ 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.EventListener;
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.Timeline; import androidx.media3.common.Timeline;
import androidx.media3.common.TrackGroup; import androidx.media3.common.TrackGroup;
import androidx.media3.common.TrackGroupArray; import androidx.media3.common.TrackGroupArray;
import androidx.media3.common.TrackSelectionArray; import androidx.media3.common.TrackSelectionArray;
import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.TrackSelectionParameters;
import androidx.media3.common.TracksInfo; import androidx.media3.common.TracksInfo;
import androidx.media3.common.VideoSize;
import androidx.media3.common.text.Cue;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.Clock; import androidx.media3.common.util.Clock;
import androidx.media3.common.util.HandlerWrapper; import androidx.media3.common.util.HandlerWrapper;
@ -78,8 +113,8 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
/** An {@link ExoPlayer} implementation. */ /** A helper class for the {@link SimpleExoPlayer} implementation of {@link ExoPlayer}. */
/* package */ final class ExoPlayerImpl extends BasePlayer { /* package */ final class ExoPlayerImpl {
static { static {
MediaLibraryInfo.registerModule("media3.exoplayer"); MediaLibraryInfo.registerModule("media3.exoplayer");
@ -97,6 +132,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
/* package */ final TrackSelectorResult emptyTrackSelectorResult; /* package */ final TrackSelectorResult emptyTrackSelectorResult;
/* package */ final Commands permanentAvailableCommands; /* package */ final Commands permanentAvailableCommands;
private final Player wrappingPlayer;
private final Renderer[] renderers; private final Renderer[] renderers;
private final TrackSelector trackSelector; private final TrackSelector trackSelector;
private final HandlerWrapper playbackInfoUpdateHandler; private final HandlerWrapper playbackInfoUpdateHandler;
@ -105,10 +141,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
private final ListenerSet<Player.EventListener> listeners; private final ListenerSet<Player.EventListener> 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 MediaSourceFactory mediaSourceFactory; private final MediaSourceFactory mediaSourceFactory;
@Nullable private final AnalyticsCollector analyticsCollector; private final AnalyticsCollector analyticsCollector;
private final Looper applicationLooper; private final Looper applicationLooper;
private final BandwidthMeter bandwidthMeter; private final BandwidthMeter bandwidthMeter;
private final long seekBackIncrementMs; private final long seekBackIncrementMs;
@ -154,16 +191,15 @@ import java.util.concurrent.CopyOnWriteArraySet;
* 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 seekParameters The {@link SeekParameters}.
* @param seekBackIncrementMs The {@link #seekBack()} increment in milliseconds. * @param seekBackIncrementMs The seek back increment in milliseconds.
* @param seekForwardIncrementMs The {@link #seekForward()} increment in milliseconds. * @param seekForwardIncrementMs The seek forward increment in milliseconds.
* @param livePlaybackSpeedControl The {@link LivePlaybackSpeedControl}. * @param livePlaybackSpeedControl The {@link LivePlaybackSpeedControl}.
* @param releaseTimeoutMs The timeout for calls to {@link #release()} in milliseconds. * @param releaseTimeoutMs The timeout for calls to {@link #release()} in milliseconds.
* @param pauseAtEndOfMediaItems Whether to pause playback at the end of each media item. * @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.
* @param wrappingPlayer The {@link Player} wrapping this one if applicable. This player instance * @param wrappingPlayer The {@link Player} using this class.
* should be used for all externally visible callbacks.
* @param additionalPermanentAvailableCommands The {@link Commands} that are permanently available * @param additionalPermanentAvailableCommands The {@link Commands} that are permanently available
* in the wrapping player but that are not in this player. * in the wrapping player but that are not in this player.
*/ */
@ -174,7 +210,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
MediaSourceFactory mediaSourceFactory, MediaSourceFactory mediaSourceFactory,
LoadControl loadControl, LoadControl loadControl,
BandwidthMeter bandwidthMeter, BandwidthMeter bandwidthMeter,
@Nullable AnalyticsCollector analyticsCollector, AnalyticsCollector analyticsCollector,
boolean useLazyPreparation, boolean useLazyPreparation,
SeekParameters seekParameters, SeekParameters seekParameters,
long seekBackIncrementMs, long seekBackIncrementMs,
@ -184,7 +220,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
boolean pauseAtEndOfMediaItems, boolean pauseAtEndOfMediaItems,
Clock clock, Clock clock,
Looper applicationLooper, Looper applicationLooper,
@Nullable Player wrappingPlayer, Player wrappingPlayer,
Commands additionalPermanentAvailableCommands) { Commands additionalPermanentAvailableCommands) {
Log.i( Log.i(
TAG, TAG,
@ -208,13 +244,13 @@ import java.util.concurrent.CopyOnWriteArraySet;
this.pauseAtEndOfMediaItems = pauseAtEndOfMediaItems; this.pauseAtEndOfMediaItems = pauseAtEndOfMediaItems;
this.applicationLooper = applicationLooper; this.applicationLooper = applicationLooper;
this.clock = clock; this.clock = clock;
this.wrappingPlayer = wrappingPlayer;
repeatMode = Player.REPEAT_MODE_OFF; repeatMode = Player.REPEAT_MODE_OFF;
Player playerForListeners = wrappingPlayer != null ? wrappingPlayer : this;
listeners = listeners =
new ListenerSet<>( new ListenerSet<>(
applicationLooper, applicationLooper,
clock, clock,
(listener, flags) -> listener.onEvents(playerForListeners, new Events(flags))); (listener, flags) -> listener.onEvents(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);
@ -225,6 +261,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
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(
@ -258,11 +295,9 @@ import java.util.concurrent.CopyOnWriteArraySet;
playbackInfoUpdate -> playbackInfoUpdate ->
playbackInfoUpdateHandler.post(() -> handlePlaybackInfo(playbackInfoUpdate)); playbackInfoUpdateHandler.post(() -> handlePlaybackInfo(playbackInfoUpdate));
playbackInfo = PlaybackInfo.createDummy(emptyTrackSelectorResult); playbackInfo = PlaybackInfo.createDummy(emptyTrackSelectorResult);
if (analyticsCollector != null) { analyticsCollector.setPlayer(wrappingPlayer, applicationLooper);
analyticsCollector.setPlayer(playerForListeners, applicationLooper); addListener(analyticsCollector);
addListener(analyticsCollector); bandwidthMeter.addEventListener(new Handler(applicationLooper), analyticsCollector);
bandwidthMeter.addEventListener(new Handler(applicationLooper), analyticsCollector);
}
PlayerId playerId = Util.SDK_INT < 31 ? new PlayerId() : Api31.createPlayerId(); PlayerId playerId = Util.SDK_INT < 31 ? new PlayerId() : Api31.createPlayerId();
internalPlayer = internalPlayer =
new ExoPlayerImplInternal( new ExoPlayerImplInternal(
@ -310,7 +345,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
return internalPlayer.getPlaybackLooper(); return internalPlayer.getPlaybackLooper();
} }
@Override
public Looper getApplicationLooper() { public Looper getApplicationLooper() {
return applicationLooper; return applicationLooper;
} }
@ -319,16 +353,10 @@ import java.util.concurrent.CopyOnWriteArraySet;
return clock; return clock;
} }
@Override
public void addListener(Listener listener) { public void addListener(Listener listener) {
addEventListener(listener); addEventListener(listener);
} }
@Override
public void removeListener(Listener listener) {
removeEventListener(listener);
}
@SuppressWarnings("deprecation") // Register deprecated EventListener. @SuppressWarnings("deprecation") // Register deprecated EventListener.
public void addEventListener(Player.EventListener eventListener) { public void addEventListener(Player.EventListener eventListener) {
listeners.add(eventListener); listeners.add(eventListener);
@ -347,24 +375,20 @@ import java.util.concurrent.CopyOnWriteArraySet;
audioOffloadListeners.remove(listener); audioOffloadListeners.remove(listener);
} }
@Override
public Commands getAvailableCommands() { public Commands getAvailableCommands() {
return availableCommands; return availableCommands;
} }
@Override
@State @State
public int getPlaybackState() { public int getPlaybackState() {
return playbackInfo.playbackState; return playbackInfo.playbackState;
} }
@Override
@PlaybackSuppressionReason @PlaybackSuppressionReason
public int getPlaybackSuppressionReason() { public int getPlaybackSuppressionReason() {
return playbackInfo.playbackSuppressionReason; return playbackInfo.playbackSuppressionReason;
} }
@Override
@Nullable @Nullable
public ExoPlaybackException getPlayerError() { public ExoPlaybackException getPlayerError() {
return playbackInfo.playbackError; return playbackInfo.playbackError;
@ -376,7 +400,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
prepare(); prepare();
} }
@Override
public void prepare() { public void prepare() {
if (playbackInfo.playbackState != Player.STATE_IDLE) { if (playbackInfo.playbackState != Player.STATE_IDLE) {
return; return;
@ -384,7 +407,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
PlaybackInfo playbackInfo = this.playbackInfo.copyWithPlaybackError(null); PlaybackInfo playbackInfo = this.playbackInfo.copyWithPlaybackError(null);
playbackInfo = playbackInfo =
playbackInfo.copyWithPlaybackState( playbackInfo.copyWithPlaybackState(
playbackInfo.timeline.isEmpty() ? Player.STATE_ENDED : Player.STATE_BUFFERING); playbackInfo.timeline.isEmpty() ? STATE_ENDED : STATE_BUFFERING);
// Trigger internal prepare first before updating the playback info and notifying external // Trigger internal prepare first before updating the playback info and notifying external
// listeners to ensure that new operations issued in the listener notifications reach the // listeners to ensure that new operations issued in the listener notifications reach the
// player after this prepare. The internal player can't change the playback info immediately // player after this prepare. The internal player can't change the playback info immediately
@ -421,12 +444,10 @@ import java.util.concurrent.CopyOnWriteArraySet;
prepare(); prepare();
} }
@Override
public void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition) { public void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition) {
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) {
setMediaSources(createMediaSources(mediaItems), startIndex, startPositionMs); setMediaSources(createMediaSources(mediaItems), startIndex, startPositionMs);
} }
@ -462,7 +483,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
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) {
index = min(index, mediaSourceHolderSnapshots.size()); index = min(index, mediaSourceHolderSnapshots.size());
addMediaSources(index, createMediaSources(mediaItems)); addMediaSources(index, createMediaSources(mediaItems));
@ -503,7 +523,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
/* ignored */ C.INDEX_UNSET); /* ignored */ C.INDEX_UNSET);
} }
@Override
public void removeMediaItems(int fromIndex, int toIndex) { public void removeMediaItems(int fromIndex, int toIndex) {
toIndex = min(toIndex, mediaSourceHolderSnapshots.size()); toIndex = min(toIndex, mediaSourceHolderSnapshots.size());
PlaybackInfo newPlaybackInfo = removeMediaItemsInternal(fromIndex, toIndex); PlaybackInfo newPlaybackInfo = removeMediaItemsInternal(fromIndex, toIndex);
@ -515,12 +534,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST, /* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
/* seekProcessed= */ false, /* seekProcessed= */ false,
positionDiscontinuity, positionDiscontinuity,
Player.DISCONTINUITY_REASON_REMOVE, DISCONTINUITY_REASON_REMOVE,
/* discontinuityWindowStartPositionUs= */ getCurrentPositionUsInternal(newPlaybackInfo), /* discontinuityWindowStartPositionUs= */ getCurrentPositionUsInternal(newPlaybackInfo),
/* 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) {
Assertions.checkArgument( Assertions.checkArgument(
fromIndex >= 0 fromIndex >= 0
@ -571,14 +589,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
/* ignored */ C.INDEX_UNSET); /* ignored */ C.INDEX_UNSET);
} }
@Override
public void setPlayWhenReady(boolean playWhenReady) {
setPlayWhenReady(
playWhenReady,
PLAYBACK_SUPPRESSION_REASON_NONE,
PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
}
public void setPauseAtEndOfMediaItems(boolean pauseAtEndOfMediaItems) { public void setPauseAtEndOfMediaItems(boolean pauseAtEndOfMediaItems) {
if (this.pauseAtEndOfMediaItems == pauseAtEndOfMediaItems) { if (this.pauseAtEndOfMediaItems == pauseAtEndOfMediaItems) {
return; return;
@ -614,12 +624,10 @@ import java.util.concurrent.CopyOnWriteArraySet;
/* ignored */ C.INDEX_UNSET); /* ignored */ C.INDEX_UNSET);
} }
@Override
public boolean getPlayWhenReady() { public boolean getPlayWhenReady() {
return playbackInfo.playWhenReady; return playbackInfo.playWhenReady;
} }
@Override
public void setRepeatMode(@RepeatMode int repeatMode) { public void setRepeatMode(@RepeatMode int repeatMode) {
if (this.repeatMode != repeatMode) { if (this.repeatMode != repeatMode) {
this.repeatMode = repeatMode; this.repeatMode = repeatMode;
@ -631,12 +639,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
} }
} }
@Override @RepeatMode
public @RepeatMode int getRepeatMode() { public int getRepeatMode() {
return repeatMode; return repeatMode;
} }
@Override
public void setShuffleModeEnabled(boolean shuffleModeEnabled) { public void setShuffleModeEnabled(boolean shuffleModeEnabled) {
if (this.shuffleModeEnabled != shuffleModeEnabled) { if (this.shuffleModeEnabled != shuffleModeEnabled) {
this.shuffleModeEnabled = shuffleModeEnabled; this.shuffleModeEnabled = shuffleModeEnabled;
@ -649,17 +656,14 @@ import java.util.concurrent.CopyOnWriteArraySet;
} }
} }
@Override
public boolean getShuffleModeEnabled() { public boolean getShuffleModeEnabled() {
return shuffleModeEnabled; return shuffleModeEnabled;
} }
@Override
public boolean isLoading() { public boolean isLoading() {
return playbackInfo.isLoading; return playbackInfo.isLoading;
} }
@Override
public void seekTo(int mediaItemIndex, long positionMs) { public void seekTo(int mediaItemIndex, long positionMs) {
Timeline timeline = playbackInfo.timeline; Timeline timeline = playbackInfo.timeline;
if (mediaItemIndex < 0 if (mediaItemIndex < 0
@ -680,7 +684,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
} }
@Player.State @Player.State
int newPlaybackState = int newPlaybackState =
getPlaybackState() == Player.STATE_IDLE ? Player.STATE_IDLE : Player.STATE_BUFFERING; getPlaybackState() == Player.STATE_IDLE ? Player.STATE_IDLE : STATE_BUFFERING;
int oldMaskingMediaItemIndex = getCurrentMediaItemIndex(); int oldMaskingMediaItemIndex = getCurrentMediaItemIndex();
PlaybackInfo newPlaybackInfo = playbackInfo.copyWithPlaybackState(newPlaybackState); PlaybackInfo newPlaybackInfo = playbackInfo.copyWithPlaybackState(newPlaybackState);
newPlaybackInfo = newPlaybackInfo =
@ -700,22 +704,18 @@ import java.util.concurrent.CopyOnWriteArraySet;
oldMaskingMediaItemIndex); oldMaskingMediaItemIndex);
} }
@Override
public long getSeekBackIncrement() { public long getSeekBackIncrement() {
return seekBackIncrementMs; return seekBackIncrementMs;
} }
@Override
public long getSeekForwardIncrement() { public long getSeekForwardIncrement() {
return seekForwardIncrementMs; return seekForwardIncrementMs;
} }
@Override
public long getMaxSeekToPreviousPosition() { public long getMaxSeekToPreviousPosition() {
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) {
if (playbackParameters == null) { if (playbackParameters == null) {
playbackParameters = PlaybackParameters.DEFAULT; playbackParameters = PlaybackParameters.DEFAULT;
@ -737,7 +737,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
/* ignored */ C.INDEX_UNSET); /* ignored */ C.INDEX_UNSET);
} }
@Override
public PlaybackParameters getPlaybackParameters() { public PlaybackParameters getPlaybackParameters() {
return playbackInfo.playbackParameters; return playbackInfo.playbackParameters;
} }
@ -770,13 +769,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
} }
} }
@Override
public void stop() {
stop(/* reset= */ false);
}
@Deprecated
@Override
public void stop(boolean reset) { public void stop(boolean reset) {
stop(reset, /* error= */ null); stop(reset, /* error= */ null);
} }
@ -819,7 +811,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
/* ignored */ C.INDEX_UNSET); /* ignored */ C.INDEX_UNSET);
} }
@Override
public void release() { public void release() {
Log.i( Log.i(
TAG, TAG,
@ -844,9 +835,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
} }
listeners.release(); listeners.release();
playbackInfoUpdateHandler.removeCallbacksAndMessages(null); playbackInfoUpdateHandler.removeCallbacksAndMessages(null);
if (analyticsCollector != null) { bandwidthMeter.removeEventListener(analyticsCollector);
bandwidthMeter.removeEventListener(analyticsCollector);
}
playbackInfo = playbackInfo.copyWithPlaybackState(Player.STATE_IDLE); playbackInfo = playbackInfo.copyWithPlaybackState(Player.STATE_IDLE);
playbackInfo = playbackInfo.copyWithLoadingMediaPeriodId(playbackInfo.periodId); playbackInfo = playbackInfo.copyWithLoadingMediaPeriodId(playbackInfo.periodId);
playbackInfo.bufferedPositionUs = playbackInfo.positionUs; playbackInfo.bufferedPositionUs = playbackInfo.positionUs;
@ -863,7 +852,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
internalPlayer.getPlaybackLooper()); internalPlayer.getPlaybackLooper());
} }
@Override
public int getCurrentPeriodIndex() { public int getCurrentPeriodIndex() {
if (playbackInfo.timeline.isEmpty()) { if (playbackInfo.timeline.isEmpty()) {
return maskingPeriodIndex; return maskingPeriodIndex;
@ -872,13 +860,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
} }
} }
@Override
public int getCurrentMediaItemIndex() { public int getCurrentMediaItemIndex() {
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() {
if (isPlayingAd()) { if (isPlayingAd()) {
MediaPeriodId periodId = playbackInfo.periodId; MediaPeriodId periodId = playbackInfo.periodId;
@ -889,12 +875,17 @@ import java.util.concurrent.CopyOnWriteArraySet;
return getContentDuration(); return getContentDuration();
} }
@Override private long getContentDuration() {
Timeline timeline = getCurrentTimeline();
return timeline.isEmpty()
? C.TIME_UNSET
: timeline.getWindow(getCurrentMediaItemIndex(), window).getDurationMs();
}
public long getCurrentPosition() { public long getCurrentPosition() {
return Util.usToMs(getCurrentPositionUsInternal(playbackInfo)); return Util.usToMs(getCurrentPositionUsInternal(playbackInfo));
} }
@Override
public long getBufferedPosition() { public long getBufferedPosition() {
if (isPlayingAd()) { if (isPlayingAd()) {
return playbackInfo.loadingMediaPeriodId.equals(playbackInfo.periodId) return playbackInfo.loadingMediaPeriodId.equals(playbackInfo.periodId)
@ -904,27 +895,22 @@ import java.util.concurrent.CopyOnWriteArraySet;
return getContentBufferedPosition(); return getContentBufferedPosition();
} }
@Override
public long getTotalBufferedDuration() { public long getTotalBufferedDuration() {
return Util.usToMs(playbackInfo.totalBufferedDurationUs); return Util.usToMs(playbackInfo.totalBufferedDurationUs);
} }
@Override
public boolean isPlayingAd() { public boolean isPlayingAd() {
return playbackInfo.periodId.isAd(); return playbackInfo.periodId.isAd();
} }
@Override
public int getCurrentAdGroupIndex() { public int getCurrentAdGroupIndex() {
return isPlayingAd() ? playbackInfo.periodId.adGroupIndex : C.INDEX_UNSET; return isPlayingAd() ? playbackInfo.periodId.adGroupIndex : C.INDEX_UNSET;
} }
@Override
public int getCurrentAdIndexInAdGroup() { public int getCurrentAdIndexInAdGroup() {
return isPlayingAd() ? playbackInfo.periodId.adIndexInAdGroup : C.INDEX_UNSET; return isPlayingAd() ? playbackInfo.periodId.adIndexInAdGroup : C.INDEX_UNSET;
} }
@Override
public long getContentPosition() { public long getContentPosition() {
if (isPlayingAd()) { if (isPlayingAd()) {
playbackInfo.timeline.getPeriodByUid(playbackInfo.periodId.periodUid, period); playbackInfo.timeline.getPeriodByUid(playbackInfo.periodId.periodUid, period);
@ -939,7 +925,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
} }
} }
@Override
public long getContentBufferedPosition() { public long getContentBufferedPosition() {
if (playbackInfo.timeline.isEmpty()) { if (playbackInfo.timeline.isEmpty()) {
return maskingWindowPositionMs; return maskingWindowPositionMs;
@ -971,32 +956,26 @@ import java.util.concurrent.CopyOnWriteArraySet;
return renderers[index].getTrackType(); return renderers[index].getTrackType();
} }
@Nullable
public TrackSelector getTrackSelector() { public TrackSelector getTrackSelector() {
return trackSelector; return trackSelector;
} }
@Override
public TrackGroupArray getCurrentTrackGroups() { public TrackGroupArray getCurrentTrackGroups() {
return playbackInfo.trackGroups; return playbackInfo.trackGroups;
} }
@Override
public TrackSelectionArray getCurrentTrackSelections() { public TrackSelectionArray getCurrentTrackSelections() {
return new TrackSelectionArray(playbackInfo.trackSelectorResult.selections); return new TrackSelectionArray(playbackInfo.trackSelectorResult.selections);
} }
@Override
public TracksInfo getCurrentTracksInfo() { public TracksInfo getCurrentTracksInfo() {
return playbackInfo.trackSelectorResult.tracksInfo; return playbackInfo.trackSelectorResult.tracksInfo;
} }
@Override
public TrackSelectionParameters getTrackSelectionParameters() { public TrackSelectionParameters getTrackSelectionParameters() {
return trackSelector.getParameters(); return trackSelector.getParameters();
} }
@Override
public void setTrackSelectionParameters(TrackSelectionParameters parameters) { public void setTrackSelectionParameters(TrackSelectionParameters parameters) {
if (!trackSelector.isSetParametersSupported() if (!trackSelector.isSetParametersSupported()
|| parameters.equals(trackSelector.getParameters())) { || parameters.equals(trackSelector.getParameters())) {
@ -1008,7 +987,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
listener -> listener.onTrackSelectionParametersChanged(parameters)); listener -> listener.onTrackSelectionParametersChanged(parameters));
} }
@Override
public MediaMetadata getMediaMetadata() { public MediaMetadata getMediaMetadata() {
return mediaMetadata; return mediaMetadata;
} }
@ -1027,12 +1005,10 @@ import java.util.concurrent.CopyOnWriteArraySet;
EVENT_MEDIA_METADATA_CHANGED, listener -> listener.onMediaMetadataChanged(mediaMetadata)); EVENT_MEDIA_METADATA_CHANGED, listener -> listener.onMediaMetadataChanged(mediaMetadata));
} }
@Override
public MediaMetadata getPlaylistMetadata() { public MediaMetadata getPlaylistMetadata() {
return playlistMetadata; return playlistMetadata;
} }
@Override
public void setPlaylistMetadata(MediaMetadata playlistMetadata) { public void setPlaylistMetadata(MediaMetadata playlistMetadata) {
checkNotNull(playlistMetadata); checkNotNull(playlistMetadata);
if (playlistMetadata.equals(this.playlistMetadata)) { if (playlistMetadata.equals(this.playlistMetadata)) {
@ -1044,109 +1020,10 @@ import java.util.concurrent.CopyOnWriteArraySet;
listener -> listener.onPlaylistMetadataChanged(this.playlistMetadata)); listener -> listener.onPlaylistMetadataChanged(this.playlistMetadata));
} }
@Override
public Timeline getCurrentTimeline() { public Timeline getCurrentTimeline() {
return playbackInfo.timeline; return playbackInfo.timeline;
} }
/** This method is not supported and returns {@link AudioAttributes#DEFAULT}. */
@Override
public AudioAttributes getAudioAttributes() {
return AudioAttributes.DEFAULT;
}
/** This method is not supported and does nothing. */
@Override
public void setVolume(float volume) {}
/** This method is not supported and returns 1. */
@Override
public float getVolume() {
return 1;
}
/** This method is not supported and does nothing. */
@Override
public void clearVideoSurface() {}
/** This method is not supported and does nothing. */
@Override
public void clearVideoSurface(@Nullable Surface surface) {}
/** This method is not supported and does nothing. */
@Override
public void setVideoSurface(@Nullable Surface surface) {}
/** This method is not supported and does nothing. */
@Override
public void setVideoSurfaceHolder(@Nullable SurfaceHolder surfaceHolder) {}
/** This method is not supported and does nothing. */
@Override
public void clearVideoSurfaceHolder(@Nullable SurfaceHolder surfaceHolder) {}
/** This method is not supported and does nothing. */
@Override
public void setVideoSurfaceView(@Nullable SurfaceView surfaceView) {}
/** This method is not supported and does nothing. */
@Override
public void clearVideoSurfaceView(@Nullable SurfaceView surfaceView) {}
/** This method is not supported and does nothing. */
@Override
public void setVideoTextureView(@Nullable TextureView textureView) {}
/** This method is not supported and does nothing. */
@Override
public void clearVideoTextureView(@Nullable TextureView textureView) {}
/** This method is not supported and returns {@link VideoSize#UNKNOWN}. */
@Override
public VideoSize getVideoSize() {
return VideoSize.UNKNOWN;
}
/** This method is not supported and returns an empty list. */
@Override
public ImmutableList<Cue> getCurrentCues() {
return ImmutableList.of();
}
/** This method is not supported and always returns {@link DeviceInfo#UNKNOWN}. */
@Override
public DeviceInfo getDeviceInfo() {
return DeviceInfo.UNKNOWN;
}
/** This method is not supported and always returns {@code 0}. */
@Override
public int getDeviceVolume() {
return 0;
}
/** This method is not supported and always returns {@link false}. */
@Override
public boolean isDeviceMuted() {
return false;
}
/** This method is not supported and does nothing. */
@Override
public void setDeviceVolume(int volume) {}
/** This method is not supported and does nothing. */
@Override
public void increaseDeviceVolume() {}
/** This method is not supported and does nothing. */
@Override
public void decreaseDeviceVolume() {}
/** This method is not supported and does nothing. */
@Override
public void setDeviceMuted(boolean muted) {}
private int getCurrentWindowIndexInternal() { private int getCurrentWindowIndexInternal() {
if (playbackInfo.timeline.isEmpty()) { if (playbackInfo.timeline.isEmpty()) {
return maskingWindowIndex; return maskingWindowIndex;
@ -1329,7 +1206,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
if (metadataChanged) { if (metadataChanged) {
final MediaMetadata finalMediaMetadata = mediaMetadata; final MediaMetadata finalMediaMetadata = mediaMetadata;
listeners.queueEvent( listeners.queueEvent(
Player.EVENT_MEDIA_METADATA_CHANGED, EVENT_MEDIA_METADATA_CHANGED,
listener -> listener.onMediaMetadataChanged(finalMediaMetadata)); listener -> listener.onMediaMetadataChanged(finalMediaMetadata));
} }
if (previousPlaybackInfo.isLoading != newPlaybackInfo.isLoading) { if (previousPlaybackInfo.isLoading != newPlaybackInfo.isLoading) {
@ -1537,7 +1414,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
private void updateAvailableCommands() { private void updateAvailableCommands() {
Commands previousAvailableCommands = availableCommands; Commands previousAvailableCommands = availableCommands;
availableCommands = getAvailableCommands(permanentAvailableCommands); availableCommands = Util.getAvailableCommands(wrappingPlayer, permanentAvailableCommands);
if (!availableCommands.equals(previousAvailableCommands)) { if (!availableCommands.equals(previousAvailableCommands)) {
listeners.queueEvent( listeners.queueEvent(
Player.EVENT_AVAILABLE_COMMANDS_CHANGED, Player.EVENT_AVAILABLE_COMMANDS_CHANGED,
@ -1599,7 +1476,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST, /* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
/* seekProcessed= */ false, /* seekProcessed= */ false,
/* positionDiscontinuity= */ positionDiscontinuity, /* positionDiscontinuity= */ positionDiscontinuity,
Player.DISCONTINUITY_REASON_REMOVE, DISCONTINUITY_REASON_REMOVE,
/* discontinuityWindowStartPositionUs= */ getCurrentPositionUsInternal(newPlaybackInfo), /* discontinuityWindowStartPositionUs= */ getCurrentPositionUsInternal(newPlaybackInfo),
/* ignored */ C.INDEX_UNSET); /* ignored */ C.INDEX_UNSET);
} }
@ -1838,12 +1715,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
* #onMetadata(Metadata)}) sources. * #onMetadata(Metadata)}) sources.
*/ */
private MediaMetadata buildUpdatedMediaMetadata() { private MediaMetadata buildUpdatedMediaMetadata() {
@Nullable MediaItem mediaItem = getCurrentMediaItem(); Timeline timeline = getCurrentTimeline();
if (timeline.isEmpty()) {
if (mediaItem == null) {
return staticAndDynamicMediaMetadata; return staticAndDynamicMediaMetadata;
} }
MediaItem mediaItem = timeline.getWindow(getCurrentMediaItemIndex(), window).mediaItem;
// MediaItem metadata is prioritized over metadata within the media. // MediaItem metadata is prioritized over metadata within the media.
return staticAndDynamicMediaMetadata.buildUpon().populate(mediaItem.mediaMetadata).build(); return staticAndDynamicMediaMetadata.buildUpon().populate(mediaItem.mediaMetadata).build();
} }

View File

@ -1362,7 +1362,6 @@ public class SimpleExoPlayer extends BasePlayer
} }
@Override @Override
@Nullable
public TrackSelector getTrackSelector() { public TrackSelector getTrackSelector() {
verifyApplicationThread(); verifyApplicationThread();
return player.getTrackSelector(); return player.getTrackSelector();