Replace SimpleBasePlayer.State.playlist by getter
The value is basically a duplicate of the information stored in the timeline field. Reducing the source of truth to the single Timeline also allows acceptance of other Timelines in the future that don't necessarily have the helper structure of the playlist. To allow apps to retrieve the current playlist as it is, we add a getter instead. PiperOrigin-RevId: 649667281
This commit is contained in:
parent
35a43d5c43
commit
fafd927702
@ -3,6 +3,7 @@
|
|||||||
### Unreleased changes
|
### Unreleased changes
|
||||||
|
|
||||||
* Common Library:
|
* Common Library:
|
||||||
|
* Replace `SimpleBasePlayer.State.playlist` by `getPlaylist()` method.
|
||||||
* ExoPlayer:
|
* ExoPlayer:
|
||||||
* `MediaCodecRenderer.onProcessedStreamChange()` can now be called for
|
* `MediaCodecRenderer.onProcessedStreamChange()` can now be called for
|
||||||
every media item. Previously it was not called for the first one. Use
|
every media item. Previously it was not called for the first one. Use
|
||||||
|
@ -53,6 +53,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||||
@ -170,7 +171,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
newlyRenderedFirstFrame = false;
|
newlyRenderedFirstFrame = false;
|
||||||
timedMetadata = new Metadata(/* presentationTimeUs= */ C.TIME_UNSET);
|
timedMetadata = new Metadata(/* presentationTimeUs= */ C.TIME_UNSET);
|
||||||
playlist = ImmutableList.of();
|
playlist = ImmutableList.of();
|
||||||
timeline = Timeline.EMPTY;
|
timeline = new PlaylistTimeline(ImmutableList.of());
|
||||||
playlistMetadata = MediaMetadata.EMPTY;
|
playlistMetadata = MediaMetadata.EMPTY;
|
||||||
currentMediaItemIndex = C.INDEX_UNSET;
|
currentMediaItemIndex = C.INDEX_UNSET;
|
||||||
currentAdGroupIndex = C.INDEX_UNSET;
|
currentAdGroupIndex = C.INDEX_UNSET;
|
||||||
@ -212,8 +213,8 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
this.surfaceSize = state.surfaceSize;
|
this.surfaceSize = state.surfaceSize;
|
||||||
this.newlyRenderedFirstFrame = state.newlyRenderedFirstFrame;
|
this.newlyRenderedFirstFrame = state.newlyRenderedFirstFrame;
|
||||||
this.timedMetadata = state.timedMetadata;
|
this.timedMetadata = state.timedMetadata;
|
||||||
this.playlist = state.playlist;
|
|
||||||
this.timeline = state.timeline;
|
this.timeline = state.timeline;
|
||||||
|
this.playlist = ((PlaylistTimeline) state.timeline).playlist;
|
||||||
this.playlistMetadata = state.playlistMetadata;
|
this.playlistMetadata = state.playlistMetadata;
|
||||||
this.currentMediaItemIndex = state.currentMediaItemIndex;
|
this.currentMediaItemIndex = state.currentMediaItemIndex;
|
||||||
this.currentAdGroupIndex = state.currentAdGroupIndex;
|
this.currentAdGroupIndex = state.currentAdGroupIndex;
|
||||||
@ -850,10 +851,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
/** The most recent timed metadata. */
|
/** The most recent timed metadata. */
|
||||||
public final Metadata timedMetadata;
|
public final Metadata timedMetadata;
|
||||||
|
|
||||||
/** The media items in the playlist. */
|
/** The {@link Timeline}. */
|
||||||
public final ImmutableList<MediaItemData> playlist;
|
|
||||||
|
|
||||||
/** The {@link Timeline} derived from the {@link #playlist}. */
|
|
||||||
public final Timeline timeline;
|
public final Timeline timeline;
|
||||||
|
|
||||||
/** The playlist {@link MediaMetadata}. */
|
/** The playlist {@link MediaMetadata}. */
|
||||||
@ -1015,7 +1013,6 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
this.surfaceSize = builder.surfaceSize;
|
this.surfaceSize = builder.surfaceSize;
|
||||||
this.newlyRenderedFirstFrame = builder.newlyRenderedFirstFrame;
|
this.newlyRenderedFirstFrame = builder.newlyRenderedFirstFrame;
|
||||||
this.timedMetadata = builder.timedMetadata;
|
this.timedMetadata = builder.timedMetadata;
|
||||||
this.playlist = builder.playlist;
|
|
||||||
this.timeline = builder.timeline;
|
this.timeline = builder.timeline;
|
||||||
this.playlistMetadata = builder.playlistMetadata;
|
this.playlistMetadata = builder.playlistMetadata;
|
||||||
this.currentMediaItemIndex = builder.currentMediaItemIndex;
|
this.currentMediaItemIndex = builder.currentMediaItemIndex;
|
||||||
@ -1036,6 +1033,15 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
return new Builder(this);
|
return new Builder(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of {@link MediaItemData} for the current playlist.
|
||||||
|
*
|
||||||
|
* @see Builder#setPlaylist(List)
|
||||||
|
*/
|
||||||
|
public ImmutableList<MediaItemData> getPlaylist() {
|
||||||
|
return ((PlaylistTimeline) timeline).playlist;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(@Nullable Object o) {
|
public boolean equals(@Nullable Object o) {
|
||||||
if (this == o) {
|
if (this == o) {
|
||||||
@ -1050,7 +1056,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
&& availableCommands.equals(state.availableCommands)
|
&& availableCommands.equals(state.availableCommands)
|
||||||
&& playbackState == state.playbackState
|
&& playbackState == state.playbackState
|
||||||
&& playbackSuppressionReason == state.playbackSuppressionReason
|
&& playbackSuppressionReason == state.playbackSuppressionReason
|
||||||
&& Util.areEqual(playerError, state.playerError)
|
&& Objects.equals(playerError, state.playerError)
|
||||||
&& repeatMode == state.repeatMode
|
&& repeatMode == state.repeatMode
|
||||||
&& shuffleModeEnabled == state.shuffleModeEnabled
|
&& shuffleModeEnabled == state.shuffleModeEnabled
|
||||||
&& isLoading == state.isLoading
|
&& isLoading == state.isLoading
|
||||||
@ -1069,7 +1075,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
&& surfaceSize.equals(state.surfaceSize)
|
&& surfaceSize.equals(state.surfaceSize)
|
||||||
&& newlyRenderedFirstFrame == state.newlyRenderedFirstFrame
|
&& newlyRenderedFirstFrame == state.newlyRenderedFirstFrame
|
||||||
&& timedMetadata.equals(state.timedMetadata)
|
&& timedMetadata.equals(state.timedMetadata)
|
||||||
&& playlist.equals(state.playlist)
|
&& timeline.equals(state.timeline)
|
||||||
&& playlistMetadata.equals(state.playlistMetadata)
|
&& playlistMetadata.equals(state.playlistMetadata)
|
||||||
&& currentMediaItemIndex == state.currentMediaItemIndex
|
&& currentMediaItemIndex == state.currentMediaItemIndex
|
||||||
&& currentAdGroupIndex == state.currentAdGroupIndex
|
&& currentAdGroupIndex == state.currentAdGroupIndex
|
||||||
@ -1112,7 +1118,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
result = 31 * result + surfaceSize.hashCode();
|
result = 31 * result + surfaceSize.hashCode();
|
||||||
result = 31 * result + (newlyRenderedFirstFrame ? 1 : 0);
|
result = 31 * result + (newlyRenderedFirstFrame ? 1 : 0);
|
||||||
result = 31 * result + timedMetadata.hashCode();
|
result = 31 * result + timedMetadata.hashCode();
|
||||||
result = 31 * result + playlist.hashCode();
|
result = 31 * result + timeline.hashCode();
|
||||||
result = 31 * result + playlistMetadata.hashCode();
|
result = 31 * result + playlistMetadata.hashCode();
|
||||||
result = 31 * result + currentMediaItemIndex;
|
result = 31 * result + currentMediaItemIndex;
|
||||||
result = 31 * result + currentAdGroupIndex;
|
result = 31 * result + currentAdGroupIndex;
|
||||||
@ -2133,7 +2139,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
placeholderPlaylist.add(getPlaceholderMediaItemData(mediaItems.get(i)));
|
placeholderPlaylist.add(getPlaceholderMediaItemData(mediaItems.get(i)));
|
||||||
}
|
}
|
||||||
return getStateWithNewPlaylistAndPosition(
|
return getStateWithNewPlaylistAndPosition(
|
||||||
state, placeholderPlaylist, startIndex, startPositionMs);
|
state, placeholderPlaylist, startIndex, startPositionMs, window);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2143,7 +2149,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
checkArgument(index >= 0);
|
checkArgument(index >= 0);
|
||||||
// Use a local copy to ensure the lambda below uses the current state value.
|
// Use a local copy to ensure the lambda below uses the current state value.
|
||||||
State state = this.state;
|
State state = this.state;
|
||||||
int playlistSize = state.playlist.size();
|
int playlistSize = state.timeline.getWindowCount();
|
||||||
if (!shouldHandleCommand(Player.COMMAND_CHANGE_MEDIA_ITEMS) || mediaItems.isEmpty()) {
|
if (!shouldHandleCommand(Player.COMMAND_CHANGE_MEDIA_ITEMS) || mediaItems.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2151,20 +2157,21 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
updateStateForPendingOperation(
|
updateStateForPendingOperation(
|
||||||
/* pendingOperation= */ handleAddMediaItems(correctedIndex, mediaItems),
|
/* pendingOperation= */ handleAddMediaItems(correctedIndex, mediaItems),
|
||||||
/* placeholderStateSupplier= */ () -> {
|
/* placeholderStateSupplier= */ () -> {
|
||||||
ArrayList<MediaItemData> placeholderPlaylist = new ArrayList<>(state.playlist);
|
List<MediaItemData> placeholderPlaylist = buildMutablePlaylistFromState(state);
|
||||||
for (int i = 0; i < mediaItems.size(); i++) {
|
for (int i = 0; i < mediaItems.size(); i++) {
|
||||||
placeholderPlaylist.add(
|
placeholderPlaylist.add(
|
||||||
i + correctedIndex, getPlaceholderMediaItemData(mediaItems.get(i)));
|
i + correctedIndex, getPlaceholderMediaItemData(mediaItems.get(i)));
|
||||||
}
|
}
|
||||||
if (!state.playlist.isEmpty()) {
|
if (!state.timeline.isEmpty()) {
|
||||||
return getStateWithNewPlaylist(state, placeholderPlaylist, period);
|
return getStateWithNewPlaylist(state, placeholderPlaylist, period, window);
|
||||||
} else {
|
} else {
|
||||||
// Handle initial position update when these are the first items added to the playlist.
|
// Handle initial position update when these are the first items added to the playlist.
|
||||||
return getStateWithNewPlaylistAndPosition(
|
return getStateWithNewPlaylistAndPosition(
|
||||||
state,
|
state,
|
||||||
placeholderPlaylist,
|
placeholderPlaylist,
|
||||||
state.currentMediaItemIndex,
|
state.currentMediaItemIndex,
|
||||||
state.contentPositionMsSupplier.get());
|
state.contentPositionMsSupplier.get(),
|
||||||
|
window);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2175,14 +2182,14 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
checkArgument(fromIndex >= 0 && toIndex >= fromIndex && newIndex >= 0);
|
checkArgument(fromIndex >= 0 && toIndex >= fromIndex && newIndex >= 0);
|
||||||
// Use a local copy to ensure the lambda below uses the current state value.
|
// Use a local copy to ensure the lambda below uses the current state value.
|
||||||
State state = this.state;
|
State state = this.state;
|
||||||
int playlistSize = state.playlist.size();
|
int playlistSize = state.timeline.getWindowCount();
|
||||||
if (!shouldHandleCommand(Player.COMMAND_CHANGE_MEDIA_ITEMS)
|
if (!shouldHandleCommand(Player.COMMAND_CHANGE_MEDIA_ITEMS)
|
||||||
|| playlistSize == 0
|
|| playlistSize == 0
|
||||||
|| fromIndex >= playlistSize) {
|
|| fromIndex >= playlistSize) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int correctedToIndex = min(toIndex, playlistSize);
|
int correctedToIndex = min(toIndex, playlistSize);
|
||||||
int correctedNewIndex = min(newIndex, state.playlist.size() - (correctedToIndex - fromIndex));
|
int correctedNewIndex = min(newIndex, playlistSize - (correctedToIndex - fromIndex));
|
||||||
if (fromIndex == correctedToIndex || correctedNewIndex == fromIndex) {
|
if (fromIndex == correctedToIndex || correctedNewIndex == fromIndex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2190,9 +2197,9 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
/* pendingOperation= */ handleMoveMediaItems(
|
/* pendingOperation= */ handleMoveMediaItems(
|
||||||
fromIndex, correctedToIndex, correctedNewIndex),
|
fromIndex, correctedToIndex, correctedNewIndex),
|
||||||
/* placeholderStateSupplier= */ () -> {
|
/* placeholderStateSupplier= */ () -> {
|
||||||
ArrayList<MediaItemData> placeholderPlaylist = new ArrayList<>(state.playlist);
|
List<MediaItemData> placeholderPlaylist = buildMutablePlaylistFromState(state);
|
||||||
Util.moveItems(placeholderPlaylist, fromIndex, correctedToIndex, correctedNewIndex);
|
Util.moveItems(placeholderPlaylist, fromIndex, correctedToIndex, correctedNewIndex);
|
||||||
return getStateWithNewPlaylist(state, placeholderPlaylist, period);
|
return getStateWithNewPlaylist(state, placeholderPlaylist, period, window);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2201,7 +2208,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
verifyApplicationThreadAndInitState();
|
verifyApplicationThreadAndInitState();
|
||||||
checkArgument(fromIndex >= 0 && fromIndex <= toIndex);
|
checkArgument(fromIndex >= 0 && fromIndex <= toIndex);
|
||||||
State state = this.state;
|
State state = this.state;
|
||||||
int playlistSize = state.playlist.size();
|
int playlistSize = state.timeline.getWindowCount();
|
||||||
if (!shouldHandleCommand(Player.COMMAND_CHANGE_MEDIA_ITEMS) || fromIndex > playlistSize) {
|
if (!shouldHandleCommand(Player.COMMAND_CHANGE_MEDIA_ITEMS) || fromIndex > playlistSize) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2209,14 +2216,14 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
updateStateForPendingOperation(
|
updateStateForPendingOperation(
|
||||||
/* pendingOperation= */ handleReplaceMediaItems(fromIndex, correctedToIndex, mediaItems),
|
/* pendingOperation= */ handleReplaceMediaItems(fromIndex, correctedToIndex, mediaItems),
|
||||||
/* placeholderStateSupplier= */ () -> {
|
/* placeholderStateSupplier= */ () -> {
|
||||||
ArrayList<MediaItemData> placeholderPlaylist = new ArrayList<>(state.playlist);
|
List<MediaItemData> placeholderPlaylist = buildMutablePlaylistFromState(state);
|
||||||
for (int i = 0; i < mediaItems.size(); i++) {
|
for (int i = 0; i < mediaItems.size(); i++) {
|
||||||
placeholderPlaylist.add(
|
placeholderPlaylist.add(
|
||||||
i + correctedToIndex, getPlaceholderMediaItemData(mediaItems.get(i)));
|
i + correctedToIndex, getPlaceholderMediaItemData(mediaItems.get(i)));
|
||||||
}
|
}
|
||||||
State updatedState;
|
State updatedState;
|
||||||
if (!state.playlist.isEmpty()) {
|
if (!state.timeline.isEmpty()) {
|
||||||
updatedState = getStateWithNewPlaylist(state, placeholderPlaylist, period);
|
updatedState = getStateWithNewPlaylist(state, placeholderPlaylist, period, window);
|
||||||
} else {
|
} else {
|
||||||
// Handle initial position update when these are the first items added to the playlist.
|
// Handle initial position update when these are the first items added to the playlist.
|
||||||
updatedState =
|
updatedState =
|
||||||
@ -2224,11 +2231,12 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
state,
|
state,
|
||||||
placeholderPlaylist,
|
placeholderPlaylist,
|
||||||
state.currentMediaItemIndex,
|
state.currentMediaItemIndex,
|
||||||
state.contentPositionMsSupplier.get());
|
state.contentPositionMsSupplier.get(),
|
||||||
|
window);
|
||||||
}
|
}
|
||||||
if (fromIndex < correctedToIndex) {
|
if (fromIndex < correctedToIndex) {
|
||||||
Util.removeRange(placeholderPlaylist, fromIndex, correctedToIndex);
|
Util.removeRange(placeholderPlaylist, fromIndex, correctedToIndex);
|
||||||
return getStateWithNewPlaylist(updatedState, placeholderPlaylist, period);
|
return getStateWithNewPlaylist(updatedState, placeholderPlaylist, period, window);
|
||||||
} else {
|
} else {
|
||||||
return updatedState;
|
return updatedState;
|
||||||
}
|
}
|
||||||
@ -2241,7 +2249,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
checkArgument(fromIndex >= 0 && toIndex >= fromIndex);
|
checkArgument(fromIndex >= 0 && toIndex >= fromIndex);
|
||||||
// Use a local copy to ensure the lambda below uses the current state value.
|
// Use a local copy to ensure the lambda below uses the current state value.
|
||||||
State state = this.state;
|
State state = this.state;
|
||||||
int playlistSize = state.playlist.size();
|
int playlistSize = state.timeline.getWindowCount();
|
||||||
if (!shouldHandleCommand(Player.COMMAND_CHANGE_MEDIA_ITEMS)
|
if (!shouldHandleCommand(Player.COMMAND_CHANGE_MEDIA_ITEMS)
|
||||||
|| playlistSize == 0
|
|| playlistSize == 0
|
||||||
|| fromIndex >= playlistSize) {
|
|| fromIndex >= playlistSize) {
|
||||||
@ -2254,9 +2262,9 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
updateStateForPendingOperation(
|
updateStateForPendingOperation(
|
||||||
/* pendingOperation= */ handleRemoveMediaItems(fromIndex, correctedToIndex),
|
/* pendingOperation= */ handleRemoveMediaItems(fromIndex, correctedToIndex),
|
||||||
/* placeholderStateSupplier= */ () -> {
|
/* placeholderStateSupplier= */ () -> {
|
||||||
ArrayList<MediaItemData> placeholderPlaylist = new ArrayList<>(state.playlist);
|
List<MediaItemData> placeholderPlaylist = buildMutablePlaylistFromState(state);
|
||||||
Util.removeRange(placeholderPlaylist, fromIndex, correctedToIndex);
|
Util.removeRange(placeholderPlaylist, fromIndex, correctedToIndex);
|
||||||
return getStateWithNewPlaylist(state, placeholderPlaylist, period);
|
return getStateWithNewPlaylist(state, placeholderPlaylist, period, window);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2361,14 +2369,14 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
boolean ignoreSeekForPlaceholderState =
|
boolean ignoreSeekForPlaceholderState =
|
||||||
mediaItemIndex == C.INDEX_UNSET
|
mediaItemIndex == C.INDEX_UNSET
|
||||||
|| isPlayingAd()
|
|| isPlayingAd()
|
||||||
|| (!state.playlist.isEmpty() && mediaItemIndex >= state.playlist.size());
|
|| (!state.timeline.isEmpty() && mediaItemIndex >= state.timeline.getWindowCount());
|
||||||
updateStateForPendingOperation(
|
updateStateForPendingOperation(
|
||||||
/* pendingOperation= */ handleSeek(mediaItemIndex, positionMs, seekCommand),
|
/* pendingOperation= */ handleSeek(mediaItemIndex, positionMs, seekCommand),
|
||||||
/* placeholderStateSupplier= */ () ->
|
/* placeholderStateSupplier= */ () ->
|
||||||
ignoreSeekForPlaceholderState
|
ignoreSeekForPlaceholderState
|
||||||
? state
|
? state
|
||||||
: getStateWithNewPlaylistAndPosition(
|
: getStateWithNewPlaylistAndPosition(
|
||||||
state, state.playlist, mediaItemIndex, positionMs),
|
state, /* newPlaylist= */ null, mediaItemIndex, positionMs, window),
|
||||||
/* forceSeekDiscontinuity= */ !ignoreSeekForPlaceholderState,
|
/* forceSeekDiscontinuity= */ !ignoreSeekForPlaceholderState,
|
||||||
isRepeatingCurrentItem);
|
isRepeatingCurrentItem);
|
||||||
}
|
}
|
||||||
@ -2427,7 +2435,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
.setPlaybackState(Player.STATE_IDLE)
|
.setPlaybackState(Player.STATE_IDLE)
|
||||||
.setTotalBufferedDurationMs(PositionSupplier.ZERO)
|
.setTotalBufferedDurationMs(PositionSupplier.ZERO)
|
||||||
.setContentBufferedPositionMs(
|
.setContentBufferedPositionMs(
|
||||||
PositionSupplier.getConstant(getContentPositionMsInternal(state)))
|
PositionSupplier.getConstant(getContentPositionMsInternal(state, window)))
|
||||||
.setAdBufferedPositionMs(state.adPositionMsSupplier)
|
.setAdBufferedPositionMs(state.adPositionMsSupplier)
|
||||||
.setIsLoading(false)
|
.setIsLoading(false)
|
||||||
.build());
|
.build());
|
||||||
@ -2452,7 +2460,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
.setPlaybackState(Player.STATE_IDLE)
|
.setPlaybackState(Player.STATE_IDLE)
|
||||||
.setTotalBufferedDurationMs(PositionSupplier.ZERO)
|
.setTotalBufferedDurationMs(PositionSupplier.ZERO)
|
||||||
.setContentBufferedPositionMs(
|
.setContentBufferedPositionMs(
|
||||||
PositionSupplier.getConstant(getContentPositionMsInternal(state)))
|
PositionSupplier.getConstant(getContentPositionMsInternal(state, window)))
|
||||||
.setAdBufferedPositionMs(state.adPositionMsSupplier)
|
.setAdBufferedPositionMs(state.adPositionMsSupplier)
|
||||||
.setIsLoading(false)
|
.setIsLoading(false)
|
||||||
.build();
|
.build();
|
||||||
@ -2581,13 +2589,15 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
@Override
|
@Override
|
||||||
public final long getContentPosition() {
|
public final long getContentPosition() {
|
||||||
verifyApplicationThreadAndInitState();
|
verifyApplicationThreadAndInitState();
|
||||||
return getContentPositionMsInternal(state);
|
return getContentPositionMsInternal(state, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final long getContentBufferedPosition() {
|
public final long getContentBufferedPosition() {
|
||||||
verifyApplicationThreadAndInitState();
|
verifyApplicationThreadAndInitState();
|
||||||
return max(getContentBufferedPositionMsInternal(state), getContentPositionMsInternal(state));
|
return max(
|
||||||
|
getContentBufferedPositionMsInternal(state, window),
|
||||||
|
getContentPositionMsInternal(state, window));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -3184,7 +3194,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
* Player#setDeviceMuted(boolean, int)}.
|
* Player#setDeviceMuted(boolean, int)}.
|
||||||
*
|
*
|
||||||
* <p>Will only be called if {@link Player#COMMAND_ADJUST_DEVICE_VOLUME} or {@link
|
* <p>Will only be called if {@link Player#COMMAND_ADJUST_DEVICE_VOLUME} or {@link
|
||||||
* Player#COMMAND_ADJUST_DEVICE_VOLUME} is available.
|
* Player#COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS} is available.
|
||||||
*
|
*
|
||||||
* @param muted Whether the device was requested to be muted.
|
* @param muted Whether the device was requested to be muted.
|
||||||
* @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}.
|
* @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}.
|
||||||
@ -3424,7 +3434,8 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
|
|
||||||
if (timelineChanged) {
|
if (timelineChanged) {
|
||||||
@Player.TimelineChangeReason
|
@Player.TimelineChangeReason
|
||||||
int timelineChangeReason = getTimelineChangeReason(previousState.playlist, newState.playlist);
|
int timelineChangeReason =
|
||||||
|
getTimelineChangeReason(previousState.timeline, newState.timeline, window);
|
||||||
listeners.queueEvent(
|
listeners.queueEvent(
|
||||||
Player.EVENT_TIMELINE_CHANGED,
|
Player.EVENT_TIMELINE_CHANGED,
|
||||||
listener -> listener.onTimelineChanged(newState.timeline, timelineChangeReason));
|
listener -> listener.onTimelineChanged(newState.timeline, timelineChangeReason));
|
||||||
@ -3451,7 +3462,8 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
MediaItem mediaItem =
|
MediaItem mediaItem =
|
||||||
newState.timeline.isEmpty()
|
newState.timeline.isEmpty()
|
||||||
? null
|
? null
|
||||||
: newState.playlist.get(getCurrentMediaItemIndexInternal(newState)).mediaItem;
|
: newState.timeline.getWindow(getCurrentMediaItemIndexInternal(newState), window)
|
||||||
|
.mediaItem;
|
||||||
listeners.queueEvent(
|
listeners.queueEvent(
|
||||||
Player.EVENT_MEDIA_ITEM_TRANSITION,
|
Player.EVENT_MEDIA_ITEM_TRANSITION,
|
||||||
listener -> listener.onMediaItemTransition(mediaItem, mediaItemTransitionReason));
|
listener -> listener.onMediaItemTransition(mediaItem, mediaItemTransitionReason));
|
||||||
@ -3676,15 +3688,17 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Tracks getCurrentTracksInternal(State state) {
|
private static Tracks getCurrentTracksInternal(State state) {
|
||||||
return state.playlist.isEmpty()
|
return state.timeline.isEmpty()
|
||||||
? Tracks.EMPTY
|
? Tracks.EMPTY
|
||||||
: state.playlist.get(getCurrentMediaItemIndexInternal(state)).tracks;
|
: ((PlaylistTimeline) state.timeline)
|
||||||
|
.playlist.get(getCurrentMediaItemIndexInternal(state)).tracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MediaMetadata getMediaMetadataInternal(State state) {
|
private static MediaMetadata getMediaMetadataInternal(State state) {
|
||||||
return state.playlist.isEmpty()
|
return state.timeline.isEmpty()
|
||||||
? MediaMetadata.EMPTY
|
? MediaMetadata.EMPTY
|
||||||
: state.playlist.get(getCurrentMediaItemIndexInternal(state)).combinedMediaMetadata;
|
: ((PlaylistTimeline) state.timeline)
|
||||||
|
.playlist.get(getCurrentMediaItemIndexInternal(state)).combinedMediaMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getCurrentMediaItemIndexInternal(State state) {
|
private static int getCurrentMediaItemIndexInternal(State state) {
|
||||||
@ -3694,22 +3708,27 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
return 0; // TODO: Use shuffle order to get first item if playlist is not empty.
|
return 0; // TODO: Use shuffle order to get first item if playlist is not empty.
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long getContentPositionMsInternal(State state) {
|
private static long getContentPositionMsInternal(State state, Timeline.Window window) {
|
||||||
return getPositionOrDefaultInMediaItem(state.contentPositionMsSupplier.get(), state);
|
return getPositionOrDefaultInMediaItem(state.contentPositionMsSupplier.get(), state, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long getContentBufferedPositionMsInternal(State state) {
|
private static long getContentBufferedPositionMsInternal(State state, Timeline.Window window) {
|
||||||
return getPositionOrDefaultInMediaItem(state.contentBufferedPositionMsSupplier.get(), state);
|
return getPositionOrDefaultInMediaItem(
|
||||||
|
state.contentBufferedPositionMsSupplier.get(), state, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long getPositionOrDefaultInMediaItem(long positionMs, State state) {
|
private static long getPositionOrDefaultInMediaItem(
|
||||||
|
long positionMs, State state, Timeline.Window window) {
|
||||||
if (positionMs != C.TIME_UNSET) {
|
if (positionMs != C.TIME_UNSET) {
|
||||||
return positionMs;
|
return positionMs;
|
||||||
}
|
}
|
||||||
if (state.playlist.isEmpty()) {
|
if (state.timeline.isEmpty()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return usToMs(state.playlist.get(getCurrentMediaItemIndexInternal(state)).defaultPositionUs);
|
return state
|
||||||
|
.timeline
|
||||||
|
.getWindow(getCurrentMediaItemIndexInternal(state), window)
|
||||||
|
.getDefaultPositionMs();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getCurrentPeriodIndexInternal(
|
private static int getCurrentPeriodIndexInternal(
|
||||||
@ -3719,7 +3738,11 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
return currentMediaItemIndex;
|
return currentMediaItemIndex;
|
||||||
}
|
}
|
||||||
return getPeriodIndexFromWindowPosition(
|
return getPeriodIndexFromWindowPosition(
|
||||||
state.timeline, currentMediaItemIndex, getContentPositionMsInternal(state), window, period);
|
state.timeline,
|
||||||
|
currentMediaItemIndex,
|
||||||
|
getContentPositionMsInternal(state, window),
|
||||||
|
window,
|
||||||
|
period);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getPeriodIndexFromWindowPosition(
|
private static int getPeriodIndexFromWindowPosition(
|
||||||
@ -3734,13 +3757,13 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static @Player.TimelineChangeReason int getTimelineChangeReason(
|
private static @Player.TimelineChangeReason int getTimelineChangeReason(
|
||||||
List<MediaItemData> previousPlaylist, List<MediaItemData> newPlaylist) {
|
Timeline previousTimeline, Timeline newTimeline, Timeline.Window window) {
|
||||||
if (previousPlaylist.size() != newPlaylist.size()) {
|
if (previousTimeline.getWindowCount() != newTimeline.getWindowCount()) {
|
||||||
return Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED;
|
return Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < previousPlaylist.size(); i++) {
|
for (int i = 0; i < previousTimeline.getWindowCount(); i++) {
|
||||||
Object previousUid = previousPlaylist.get(i).uid;
|
Object previousUid = previousTimeline.getWindow(/* windowIndex= */ i, window).uid;
|
||||||
Object newUid = newPlaylist.get(i).uid;
|
Object newUid = newTimeline.getWindow(/* windowIndex= */ i, window).uid;
|
||||||
boolean resolvedAutoGeneratedPlaceholder =
|
boolean resolvedAutoGeneratedPlaceholder =
|
||||||
previousUid instanceof PlaceholderUid && !(newUid instanceof PlaceholderUid);
|
previousUid instanceof PlaceholderUid && !(newUid instanceof PlaceholderUid);
|
||||||
if (!previousUid.equals(newUid) && !resolvedAutoGeneratedPlaceholder) {
|
if (!previousUid.equals(newUid) && !resolvedAutoGeneratedPlaceholder) {
|
||||||
@ -3763,11 +3786,11 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
if (forceSeekDiscontinuity) {
|
if (forceSeekDiscontinuity) {
|
||||||
return Player.DISCONTINUITY_REASON_SEEK;
|
return Player.DISCONTINUITY_REASON_SEEK;
|
||||||
}
|
}
|
||||||
if (previousState.playlist.isEmpty()) {
|
if (previousState.timeline.isEmpty()) {
|
||||||
// First change from an empty playlist is not reported as a discontinuity.
|
// First change from an empty playlist is not reported as a discontinuity.
|
||||||
return C.INDEX_UNSET;
|
return C.INDEX_UNSET;
|
||||||
}
|
}
|
||||||
if (newState.playlist.isEmpty()) {
|
if (newState.timeline.isEmpty()) {
|
||||||
// The playlist became empty.
|
// The playlist became empty.
|
||||||
return Player.DISCONTINUITY_REASON_REMOVE;
|
return Player.DISCONTINUITY_REASON_REMOVE;
|
||||||
}
|
}
|
||||||
@ -3790,7 +3813,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
}
|
}
|
||||||
// Check if reached the previous period's or ad's duration to assume an auto-transition.
|
// Check if reached the previous period's or ad's duration to assume an auto-transition.
|
||||||
long previousPositionMs =
|
long previousPositionMs =
|
||||||
getCurrentPeriodOrAdPositionMs(previousState, previousPeriodUid, period);
|
getCurrentPeriodOrAdPositionMs(previousState, previousPeriodUid, period, window);
|
||||||
long previousDurationMs = getPeriodOrAdDurationMs(previousState, previousPeriodUid, period);
|
long previousDurationMs = getPeriodOrAdDurationMs(previousState, previousPeriodUid, period);
|
||||||
return previousDurationMs != C.TIME_UNSET && previousPositionMs >= previousDurationMs
|
return previousDurationMs != C.TIME_UNSET && previousPositionMs >= previousDurationMs
|
||||||
? Player.DISCONTINUITY_REASON_AUTO_TRANSITION
|
? Player.DISCONTINUITY_REASON_AUTO_TRANSITION
|
||||||
@ -3799,8 +3822,8 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
// We are in the same content period or ad. Check if the position deviates more than a
|
// We are in the same content period or ad. Check if the position deviates more than a
|
||||||
// reasonable threshold from the previous one.
|
// reasonable threshold from the previous one.
|
||||||
long previousPositionMs =
|
long previousPositionMs =
|
||||||
getCurrentPeriodOrAdPositionMs(previousState, previousPeriodUid, period);
|
getCurrentPeriodOrAdPositionMs(previousState, previousPeriodUid, period, window);
|
||||||
long newPositionMs = getCurrentPeriodOrAdPositionMs(newState, newPeriodUid, period);
|
long newPositionMs = getCurrentPeriodOrAdPositionMs(newState, newPeriodUid, period, window);
|
||||||
if (Math.abs(previousPositionMs - newPositionMs) < POSITION_DISCONTINUITY_THRESHOLD_MS) {
|
if (Math.abs(previousPositionMs - newPositionMs) < POSITION_DISCONTINUITY_THRESHOLD_MS) {
|
||||||
return C.INDEX_UNSET;
|
return C.INDEX_UNSET;
|
||||||
}
|
}
|
||||||
@ -3812,10 +3835,10 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static long getCurrentPeriodOrAdPositionMs(
|
private static long getCurrentPeriodOrAdPositionMs(
|
||||||
State state, Object currentPeriodUid, Timeline.Period period) {
|
State state, Object currentPeriodUid, Timeline.Period period, Timeline.Window window) {
|
||||||
return state.currentAdGroupIndex != C.INDEX_UNSET
|
return state.currentAdGroupIndex != C.INDEX_UNSET
|
||||||
? state.adPositionMsSupplier.get()
|
? state.adPositionMsSupplier.get()
|
||||||
: getContentPositionMsInternal(state)
|
: getContentPositionMsInternal(state, window)
|
||||||
- state.timeline.getPeriodByUid(currentPeriodUid, period).getPositionInWindowMs();
|
- state.timeline.getPeriodByUid(currentPeriodUid, period).getPositionInWindowMs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3852,9 +3875,9 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
contentPositionMs =
|
contentPositionMs =
|
||||||
state.currentAdGroupIndex == C.INDEX_UNSET
|
state.currentAdGroupIndex == C.INDEX_UNSET
|
||||||
? positionMs
|
? positionMs
|
||||||
: getContentPositionMsInternal(state);
|
: getContentPositionMsInternal(state, window);
|
||||||
} else {
|
} else {
|
||||||
contentPositionMs = getContentPositionMsInternal(state);
|
contentPositionMs = getContentPositionMsInternal(state, window);
|
||||||
positionMs =
|
positionMs =
|
||||||
state.currentAdGroupIndex != C.INDEX_UNSET
|
state.currentAdGroupIndex != C.INDEX_UNSET
|
||||||
? state.adPositionMsSupplier.get()
|
? state.adPositionMsSupplier.get()
|
||||||
@ -3906,7 +3929,8 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
// Only mark changes within the current item as a transition if we are repeating automatically
|
// Only mark changes within the current item as a transition if we are repeating automatically
|
||||||
// or via a seek to next/previous.
|
// or via a seek to next/previous.
|
||||||
if (positionDiscontinuityReason == DISCONTINUITY_REASON_AUTO_TRANSITION
|
if (positionDiscontinuityReason == DISCONTINUITY_REASON_AUTO_TRANSITION
|
||||||
&& getContentPositionMsInternal(previousState) > getContentPositionMsInternal(newState)) {
|
&& getContentPositionMsInternal(previousState, window)
|
||||||
|
> getContentPositionMsInternal(newState, window)) {
|
||||||
return MEDIA_ITEM_TRANSITION_REASON_REPEAT;
|
return MEDIA_ITEM_TRANSITION_REASON_REPEAT;
|
||||||
}
|
}
|
||||||
if (positionDiscontinuityReason == DISCONTINUITY_REASON_SEEK && isRepeatingCurrentItem) {
|
if (positionDiscontinuityReason == DISCONTINUITY_REASON_SEEK && isRepeatingCurrentItem) {
|
||||||
@ -3924,38 +3948,43 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static int getMediaItemIndexInNewPlaylist(
|
private static int getMediaItemIndexInNewPlaylist(
|
||||||
List<MediaItemData> oldPlaylist,
|
Timeline oldTimeline,
|
||||||
Timeline newPlaylistTimeline,
|
Timeline newTimeline,
|
||||||
int oldMediaItemIndex,
|
int oldMediaItemIndex,
|
||||||
Timeline.Period period) {
|
Timeline.Period period,
|
||||||
if (oldPlaylist.isEmpty()) {
|
Timeline.Window window) {
|
||||||
return oldMediaItemIndex < newPlaylistTimeline.getWindowCount()
|
if (oldTimeline.isEmpty()) {
|
||||||
? oldMediaItemIndex
|
return oldMediaItemIndex < newTimeline.getWindowCount() ? oldMediaItemIndex : C.INDEX_UNSET;
|
||||||
: C.INDEX_UNSET;
|
|
||||||
}
|
}
|
||||||
|
int oldFirstPeriodIndex = oldTimeline.getWindow(oldMediaItemIndex, window).firstPeriodIndex;
|
||||||
Object oldFirstPeriodUid =
|
Object oldFirstPeriodUid =
|
||||||
oldPlaylist.get(oldMediaItemIndex).getPeriodUid(/* periodIndexInMediaItem= */ 0);
|
checkNotNull(oldTimeline.getPeriod(oldFirstPeriodIndex, period, /* setIds= */ true).uid);
|
||||||
if (newPlaylistTimeline.getIndexOfPeriod(oldFirstPeriodUid) == C.INDEX_UNSET) {
|
if (newTimeline.getIndexOfPeriod(oldFirstPeriodUid) == C.INDEX_UNSET) {
|
||||||
return C.INDEX_UNSET;
|
return C.INDEX_UNSET;
|
||||||
}
|
}
|
||||||
return newPlaylistTimeline.getPeriodByUid(oldFirstPeriodUid, period).windowIndex;
|
return newTimeline.getPeriodByUid(oldFirstPeriodUid, period).windowIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static State getStateWithNewPlaylist(
|
private static State getStateWithNewPlaylist(
|
||||||
State oldState, List<MediaItemData> newPlaylist, Timeline.Period period) {
|
State oldState,
|
||||||
|
List<MediaItemData> newPlaylist,
|
||||||
|
Timeline.Period period,
|
||||||
|
Timeline.Window window) {
|
||||||
State.Builder stateBuilder = oldState.buildUpon();
|
State.Builder stateBuilder = oldState.buildUpon();
|
||||||
stateBuilder.setPlaylist(newPlaylist);
|
stateBuilder.setPlaylist(newPlaylist);
|
||||||
Timeline newTimeline = stateBuilder.timeline;
|
Timeline newTimeline = stateBuilder.timeline;
|
||||||
|
Timeline oldTimeline = oldState.timeline;
|
||||||
long oldPositionMs = oldState.contentPositionMsSupplier.get();
|
long oldPositionMs = oldState.contentPositionMsSupplier.get();
|
||||||
int oldIndex = getCurrentMediaItemIndexInternal(oldState);
|
int oldIndex = getCurrentMediaItemIndexInternal(oldState);
|
||||||
int newIndex = getMediaItemIndexInNewPlaylist(oldState.playlist, newTimeline, oldIndex, period);
|
int newIndex =
|
||||||
|
getMediaItemIndexInNewPlaylist(oldTimeline, newTimeline, oldIndex, period, window);
|
||||||
long newPositionMs = newIndex == C.INDEX_UNSET ? C.TIME_UNSET : oldPositionMs;
|
long newPositionMs = newIndex == C.INDEX_UNSET ? C.TIME_UNSET : oldPositionMs;
|
||||||
// If the current item no longer exists, try to find a matching subsequent item.
|
// If the current item no longer exists, try to find a matching subsequent item.
|
||||||
for (int i = oldIndex + 1; newIndex == C.INDEX_UNSET && i < oldState.playlist.size(); i++) {
|
for (int i = oldIndex + 1; newIndex == C.INDEX_UNSET && i < oldTimeline.getWindowCount(); i++) {
|
||||||
// TODO: Use shuffle order to iterate.
|
// TODO: Use shuffle order to iterate.
|
||||||
newIndex =
|
newIndex =
|
||||||
getMediaItemIndexInNewPlaylist(
|
getMediaItemIndexInNewPlaylist(
|
||||||
oldState.playlist, newTimeline, /* oldMediaItemIndex= */ i, period);
|
oldTimeline, newTimeline, /* oldMediaItemIndex= */ i, period, window);
|
||||||
}
|
}
|
||||||
// If this fails, transition to ENDED state.
|
// If this fails, transition to ENDED state.
|
||||||
if (oldState.playbackState != Player.STATE_IDLE && newIndex == C.INDEX_UNSET) {
|
if (oldState.playbackState != Player.STATE_IDLE && newIndex == C.INDEX_UNSET) {
|
||||||
@ -3965,18 +3994,28 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
stateBuilder,
|
stateBuilder,
|
||||||
oldState,
|
oldState,
|
||||||
oldPositionMs,
|
oldPositionMs,
|
||||||
newPlaylist,
|
newTimeline,
|
||||||
newIndex,
|
newIndex,
|
||||||
newPositionMs,
|
newPositionMs,
|
||||||
/* keepAds= */ true);
|
/* keepAds= */ true,
|
||||||
|
window);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static State getStateWithNewPlaylistAndPosition(
|
private static State getStateWithNewPlaylistAndPosition(
|
||||||
State oldState, List<MediaItemData> newPlaylist, int newIndex, long newPositionMs) {
|
State oldState,
|
||||||
|
@Nullable List<MediaItemData> newPlaylist,
|
||||||
|
int newIndex,
|
||||||
|
long newPositionMs,
|
||||||
|
Timeline.Window window) {
|
||||||
State.Builder stateBuilder = oldState.buildUpon();
|
State.Builder stateBuilder = oldState.buildUpon();
|
||||||
stateBuilder.setPlaylist(newPlaylist);
|
Timeline newTimeline = oldState.timeline;
|
||||||
|
if (newPlaylist != null) {
|
||||||
|
stateBuilder.setPlaylist(newPlaylist);
|
||||||
|
newTimeline = stateBuilder.timeline;
|
||||||
|
}
|
||||||
if (oldState.playbackState != Player.STATE_IDLE) {
|
if (oldState.playbackState != Player.STATE_IDLE) {
|
||||||
if (newPlaylist.isEmpty() || (newIndex != C.INDEX_UNSET && newIndex >= newPlaylist.size())) {
|
if (newTimeline.isEmpty()
|
||||||
|
|| (newIndex != C.INDEX_UNSET && newIndex >= newTimeline.getWindowCount())) {
|
||||||
stateBuilder.setPlaybackState(Player.STATE_ENDED).setIsLoading(false);
|
stateBuilder.setPlaybackState(Player.STATE_ENDED).setIsLoading(false);
|
||||||
} else {
|
} else {
|
||||||
stateBuilder.setPlaybackState(Player.STATE_BUFFERING);
|
stateBuilder.setPlaybackState(Player.STATE_BUFFERING);
|
||||||
@ -3987,37 +4026,40 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
stateBuilder,
|
stateBuilder,
|
||||||
oldState,
|
oldState,
|
||||||
oldPositionMs,
|
oldPositionMs,
|
||||||
newPlaylist,
|
newTimeline,
|
||||||
newIndex,
|
newIndex,
|
||||||
newPositionMs,
|
newPositionMs,
|
||||||
/* keepAds= */ false);
|
/* keepAds= */ false,
|
||||||
|
window);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static State buildStateForNewPosition(
|
private static State buildStateForNewPosition(
|
||||||
State.Builder stateBuilder,
|
State.Builder stateBuilder,
|
||||||
State oldState,
|
State oldState,
|
||||||
long oldPositionMs,
|
long oldPositionMs,
|
||||||
List<MediaItemData> newPlaylist,
|
Timeline newTimeline,
|
||||||
int newIndex,
|
int newIndex,
|
||||||
long newPositionMs,
|
long newPositionMs,
|
||||||
boolean keepAds) {
|
boolean keepAds,
|
||||||
|
Timeline.Window window) {
|
||||||
// Resolve unset or invalid index and position.
|
// Resolve unset or invalid index and position.
|
||||||
oldPositionMs = getPositionOrDefaultInMediaItem(oldPositionMs, oldState);
|
oldPositionMs = getPositionOrDefaultInMediaItem(oldPositionMs, oldState, window);
|
||||||
if (!newPlaylist.isEmpty() && (newIndex == C.INDEX_UNSET || newIndex >= newPlaylist.size())) {
|
if (!newTimeline.isEmpty()
|
||||||
|
&& (newIndex == C.INDEX_UNSET || newIndex >= newTimeline.getWindowCount())) {
|
||||||
newIndex = 0; // TODO: Use shuffle order to get first index.
|
newIndex = 0; // TODO: Use shuffle order to get first index.
|
||||||
newPositionMs = C.TIME_UNSET;
|
newPositionMs = C.TIME_UNSET;
|
||||||
}
|
}
|
||||||
if (!newPlaylist.isEmpty() && newPositionMs == C.TIME_UNSET) {
|
if (!newTimeline.isEmpty() && newPositionMs == C.TIME_UNSET) {
|
||||||
newPositionMs = usToMs(newPlaylist.get(newIndex).defaultPositionUs);
|
newPositionMs = newTimeline.getWindow(newIndex, window).getDefaultPositionMs();
|
||||||
}
|
}
|
||||||
boolean oldOrNewPlaylistEmpty = oldState.playlist.isEmpty() || newPlaylist.isEmpty();
|
boolean oldOrNewPlaylistEmpty = oldState.timeline.isEmpty() || newTimeline.isEmpty();
|
||||||
boolean mediaItemChanged =
|
boolean mediaItemChanged =
|
||||||
!oldOrNewPlaylistEmpty
|
!oldOrNewPlaylistEmpty
|
||||||
&& !oldState
|
&& !oldState
|
||||||
.playlist
|
.timeline
|
||||||
.get(getCurrentMediaItemIndexInternal(oldState))
|
.getWindow(getCurrentMediaItemIndexInternal(oldState), window)
|
||||||
.uid
|
.uid
|
||||||
.equals(newPlaylist.get(newIndex).uid);
|
.equals(newTimeline.getWindow(newIndex, window).uid);
|
||||||
if (oldOrNewPlaylistEmpty || mediaItemChanged || newPositionMs < oldPositionMs) {
|
if (oldOrNewPlaylistEmpty || mediaItemChanged || newPositionMs < oldPositionMs) {
|
||||||
// New item or seeking back. Assume no buffer and no ad playback persists.
|
// New item or seeking back. Assume no buffer and no ad playback persists.
|
||||||
stateBuilder
|
stateBuilder
|
||||||
@ -4038,12 +4080,12 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
.setCurrentAd(C.INDEX_UNSET, C.INDEX_UNSET)
|
.setCurrentAd(C.INDEX_UNSET, C.INDEX_UNSET)
|
||||||
.setTotalBufferedDurationMs(
|
.setTotalBufferedDurationMs(
|
||||||
PositionSupplier.getConstant(
|
PositionSupplier.getConstant(
|
||||||
getContentBufferedPositionMsInternal(oldState) - oldPositionMs));
|
getContentBufferedPositionMsInternal(oldState, window) - oldPositionMs));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Seeking forward. Assume remaining buffer in current item persist, but no ad playback.
|
// Seeking forward. Assume remaining buffer in current item persist, but no ad playback.
|
||||||
long contentBufferedDurationMs =
|
long contentBufferedDurationMs =
|
||||||
max(getContentBufferedPositionMsInternal(oldState), newPositionMs);
|
max(getContentBufferedPositionMsInternal(oldState, window), newPositionMs);
|
||||||
long totalBufferedDurationMs =
|
long totalBufferedDurationMs =
|
||||||
max(0, oldState.totalBufferedDurationMsSupplier.get() - (newPositionMs - oldPositionMs));
|
max(0, oldState.totalBufferedDurationMsSupplier.get() - (newPositionMs - oldPositionMs));
|
||||||
stateBuilder
|
stateBuilder
|
||||||
@ -4056,5 +4098,9 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
return stateBuilder.build();
|
return stateBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<MediaItemData> buildMutablePlaylistFromState(State state) {
|
||||||
|
return new ArrayList<>(((PlaylistTimeline) state.timeline).playlist);
|
||||||
|
}
|
||||||
|
|
||||||
private static final class PlaceholderUid {}
|
private static final class PlaceholderUid {}
|
||||||
}
|
}
|
||||||
|
@ -312,7 +312,8 @@ public class SimpleBasePlayerTest {
|
|||||||
assertThat(state.surfaceSize).isEqualTo(surfaceSize);
|
assertThat(state.surfaceSize).isEqualTo(surfaceSize);
|
||||||
assertThat(state.newlyRenderedFirstFrame).isTrue();
|
assertThat(state.newlyRenderedFirstFrame).isTrue();
|
||||||
assertThat(state.timedMetadata).isEqualTo(timedMetadata);
|
assertThat(state.timedMetadata).isEqualTo(timedMetadata);
|
||||||
assertThat(state.playlist).isEqualTo(playlist);
|
assertThat(state.getPlaylist()).isEqualTo(playlist);
|
||||||
|
assertThat(state.timeline.getWindowCount()).isEqualTo(2);
|
||||||
assertThat(state.playlistMetadata).isEqualTo(playlistMetadata);
|
assertThat(state.playlistMetadata).isEqualTo(playlistMetadata);
|
||||||
assertThat(state.currentMediaItemIndex).isEqualTo(1);
|
assertThat(state.currentMediaItemIndex).isEqualTo(1);
|
||||||
assertThat(state.currentAdGroupIndex).isEqualTo(1);
|
assertThat(state.currentAdGroupIndex).isEqualTo(1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user