mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Add Player.EventListener.onMediaItemTransition
PiperOrigin-RevId: 321218451
This commit is contained in:
parent
e486dc602c
commit
e7b76354b9
9 changed files with 578 additions and 10 deletions
|
|
@ -31,9 +31,10 @@
|
||||||
* Add `play` and `pause` methods to `Player`.
|
* Add `play` and `pause` methods to `Player`.
|
||||||
* Add `Player.getCurrentLiveOffset` to conveniently return the live
|
* Add `Player.getCurrentLiveOffset` to conveniently return the live
|
||||||
offset.
|
offset.
|
||||||
* Add `Player.onPlayWhenReadyChanged` with reasons.
|
* Add `Player.EventListener.onPlayWhenReadyChanged` with reasons.
|
||||||
* Add `Player.onPlaybackStateChanged` and deprecate
|
* Add `Player.EventListener.onPlaybackStateChanged` and deprecate
|
||||||
`Player.onPlayerStateChanged`.
|
`Player.EventListener.onPlayerStateChanged`.
|
||||||
|
* Add `Player.EventListener.onMediaItemTransition` with reasons.
|
||||||
* Add `Player.setAudioSessionId` to set the session ID attached to the
|
* Add `Player.setAudioSessionId` to set the session ID attached to the
|
||||||
`AudioTrack`.
|
`AudioTrack`.
|
||||||
* Deprecate and rename `getPlaybackError` to `getPlayerError` for
|
* Deprecate and rename `getPlaybackError` to `getPlayerError` for
|
||||||
|
|
@ -242,9 +243,8 @@
|
||||||
* Cast extension: Implement playlist API and deprecate the old queue
|
* Cast extension: Implement playlist API and deprecate the old queue
|
||||||
manipulation API.
|
manipulation API.
|
||||||
* IMA extension:
|
* IMA extension:
|
||||||
* Upgrade to IMA SDK 3.19.4, bringing in a fix for setting the
|
* Upgrade to IMA SDK 3.19.4, bringing in a fix for setting the media load
|
||||||
media load timeout
|
timeout ([#7170](https://github.com/google/ExoPlayer/issues/7170)).
|
||||||
([#7170](https://github.com/google/ExoPlayer/issues/7170)).
|
|
||||||
* Migrate to new 'friendly obstruction' IMA SDK APIs, and allow apps to
|
* Migrate to new 'friendly obstruction' IMA SDK APIs, and allow apps to
|
||||||
register a purpose and detail reason for overlay views via
|
register a purpose and detail reason for overlay views via
|
||||||
`AdsLoader.AdViewProvider`.
|
`AdsLoader.AdViewProvider`.
|
||||||
|
|
|
||||||
|
|
@ -990,6 +990,22 @@ import java.util.concurrent.TimeoutException;
|
||||||
// Assign playback info immediately such that all getters return the right values.
|
// Assign playback info immediately such that all getters return the right values.
|
||||||
PlaybackInfo previousPlaybackInfo = this.playbackInfo;
|
PlaybackInfo previousPlaybackInfo = this.playbackInfo;
|
||||||
this.playbackInfo = playbackInfo;
|
this.playbackInfo = playbackInfo;
|
||||||
|
|
||||||
|
Pair<Boolean, Integer> mediaItemTransitionInfo =
|
||||||
|
evaluateMediaItemTransitionReason(
|
||||||
|
playbackInfo,
|
||||||
|
previousPlaybackInfo,
|
||||||
|
positionDiscontinuity,
|
||||||
|
positionDiscontinuityReason,
|
||||||
|
!previousPlaybackInfo.timeline.equals(playbackInfo.timeline));
|
||||||
|
boolean mediaItemTransitioned = mediaItemTransitionInfo.first;
|
||||||
|
int mediaItemTransitionReason = mediaItemTransitionInfo.second;
|
||||||
|
@Nullable MediaItem newMediaItem = null;
|
||||||
|
if (mediaItemTransitioned && !playbackInfo.timeline.isEmpty()) {
|
||||||
|
int windowIndex =
|
||||||
|
playbackInfo.timeline.getPeriodByUid(playbackInfo.periodId.periodUid, period).windowIndex;
|
||||||
|
newMediaItem = playbackInfo.timeline.getWindow(windowIndex, window).mediaItem;
|
||||||
|
}
|
||||||
notifyListeners(
|
notifyListeners(
|
||||||
new PlaybackInfoUpdate(
|
new PlaybackInfoUpdate(
|
||||||
playbackInfo,
|
playbackInfo,
|
||||||
|
|
@ -999,10 +1015,58 @@ import java.util.concurrent.TimeoutException;
|
||||||
positionDiscontinuity,
|
positionDiscontinuity,
|
||||||
positionDiscontinuityReason,
|
positionDiscontinuityReason,
|
||||||
timelineChangeReason,
|
timelineChangeReason,
|
||||||
|
mediaItemTransitioned,
|
||||||
|
mediaItemTransitionReason,
|
||||||
|
newMediaItem,
|
||||||
playWhenReadyChangeReason,
|
playWhenReadyChangeReason,
|
||||||
seekProcessed));
|
seekProcessed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Pair<Boolean, Integer> evaluateMediaItemTransitionReason(
|
||||||
|
PlaybackInfo playbackInfo,
|
||||||
|
PlaybackInfo oldPlaybackInfo,
|
||||||
|
boolean positionDiscontinuity,
|
||||||
|
int positionDiscontinuityReason,
|
||||||
|
boolean timelineChanged) {
|
||||||
|
|
||||||
|
Timeline oldTimeline = oldPlaybackInfo.timeline;
|
||||||
|
Timeline newTimeline = playbackInfo.timeline;
|
||||||
|
if (newTimeline.isEmpty() && oldTimeline.isEmpty()) {
|
||||||
|
return new Pair<>(/* isTransitioning */ false, /* mediaItemTransitionReason */ C.INDEX_UNSET);
|
||||||
|
} else if (newTimeline.isEmpty() != oldTimeline.isEmpty()) {
|
||||||
|
return new Pair<>(/* isTransitioning */ true, MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
int oldWindowIndex =
|
||||||
|
oldTimeline.getPeriodByUid(oldPlaybackInfo.periodId.periodUid, period).windowIndex;
|
||||||
|
Object oldWindowUid = oldTimeline.getWindow(oldWindowIndex, window).uid;
|
||||||
|
int newWindowIndex =
|
||||||
|
newTimeline.getPeriodByUid(playbackInfo.periodId.periodUid, period).windowIndex;
|
||||||
|
Object newWindowUid = newTimeline.getWindow(newWindowIndex, window).uid;
|
||||||
|
int firstPeriodIndexInNewWindow = window.firstPeriodIndex;
|
||||||
|
if (!oldWindowUid.equals(newWindowUid)) {
|
||||||
|
@Player.MediaItemTransitionReason int transitionReason;
|
||||||
|
if (positionDiscontinuity
|
||||||
|
&& positionDiscontinuityReason == DISCONTINUITY_REASON_PERIOD_TRANSITION) {
|
||||||
|
transitionReason = MEDIA_ITEM_TRANSITION_REASON_AUTO;
|
||||||
|
} else if (positionDiscontinuity
|
||||||
|
&& positionDiscontinuityReason == DISCONTINUITY_REASON_SEEK) {
|
||||||
|
transitionReason = MEDIA_ITEM_TRANSITION_REASON_SEEK;
|
||||||
|
} else if (timelineChanged) {
|
||||||
|
transitionReason = MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED;
|
||||||
|
} else {
|
||||||
|
transitionReason = MEDIA_ITEM_TRANSITION_REASON_SKIP;
|
||||||
|
}
|
||||||
|
return new Pair<>(/* isTransitioning */ true, transitionReason);
|
||||||
|
} else if (positionDiscontinuity
|
||||||
|
&& positionDiscontinuityReason == DISCONTINUITY_REASON_PERIOD_TRANSITION
|
||||||
|
&& newTimeline.getIndexOfPeriod(playbackInfo.periodId.periodUid)
|
||||||
|
== firstPeriodIndexInNewWindow) {
|
||||||
|
return new Pair<>(/* isTransitioning */ true, MEDIA_ITEM_TRANSITION_REASON_REPEAT);
|
||||||
|
}
|
||||||
|
return new Pair<>(/* isTransitioning */ false, /* mediaItemTransitionReason */ C.INDEX_UNSET);
|
||||||
|
}
|
||||||
|
|
||||||
private void setMediaSourcesInternal(
|
private void setMediaSourcesInternal(
|
||||||
List<MediaSource> mediaSources,
|
List<MediaSource> mediaSources,
|
||||||
int startWindowIndex,
|
int startWindowIndex,
|
||||||
|
|
@ -1388,16 +1452,19 @@ import java.util.concurrent.TimeoutException;
|
||||||
private final boolean positionDiscontinuity;
|
private final boolean positionDiscontinuity;
|
||||||
@DiscontinuityReason private final int positionDiscontinuityReason;
|
@DiscontinuityReason private final int positionDiscontinuityReason;
|
||||||
@TimelineChangeReason private final int timelineChangeReason;
|
@TimelineChangeReason private final int timelineChangeReason;
|
||||||
|
private final boolean mediaItemTransitioned;
|
||||||
|
private final int mediaItemTransitionReason;
|
||||||
|
@Nullable private final MediaItem mediaItem;
|
||||||
@PlayWhenReadyChangeReason private final int playWhenReadyChangeReason;
|
@PlayWhenReadyChangeReason private final int playWhenReadyChangeReason;
|
||||||
private final boolean seekProcessed;
|
private final boolean seekProcessed;
|
||||||
private final boolean playbackStateChanged;
|
private final boolean playbackStateChanged;
|
||||||
private final boolean playbackErrorChanged;
|
private final boolean playbackErrorChanged;
|
||||||
private final boolean timelineChanged;
|
|
||||||
private final boolean isLoadingChanged;
|
private final boolean isLoadingChanged;
|
||||||
|
private final boolean timelineChanged;
|
||||||
private final boolean trackSelectorResultChanged;
|
private final boolean trackSelectorResultChanged;
|
||||||
private final boolean isPlayingChanged;
|
|
||||||
private final boolean playWhenReadyChanged;
|
private final boolean playWhenReadyChanged;
|
||||||
private final boolean playbackSuppressionReasonChanged;
|
private final boolean playbackSuppressionReasonChanged;
|
||||||
|
private final boolean isPlayingChanged;
|
||||||
|
|
||||||
public PlaybackInfoUpdate(
|
public PlaybackInfoUpdate(
|
||||||
PlaybackInfo playbackInfo,
|
PlaybackInfo playbackInfo,
|
||||||
|
|
@ -1407,6 +1474,9 @@ import java.util.concurrent.TimeoutException;
|
||||||
boolean positionDiscontinuity,
|
boolean positionDiscontinuity,
|
||||||
@DiscontinuityReason int positionDiscontinuityReason,
|
@DiscontinuityReason int positionDiscontinuityReason,
|
||||||
@TimelineChangeReason int timelineChangeReason,
|
@TimelineChangeReason int timelineChangeReason,
|
||||||
|
boolean mediaItemTransitioned,
|
||||||
|
@MediaItemTransitionReason int mediaItemTransitionReason,
|
||||||
|
@Nullable MediaItem mediaItem,
|
||||||
@PlayWhenReadyChangeReason int playWhenReadyChangeReason,
|
@PlayWhenReadyChangeReason int playWhenReadyChangeReason,
|
||||||
boolean seekProcessed) {
|
boolean seekProcessed) {
|
||||||
this.playbackInfo = playbackInfo;
|
this.playbackInfo = playbackInfo;
|
||||||
|
|
@ -1415,6 +1485,9 @@ import java.util.concurrent.TimeoutException;
|
||||||
this.positionDiscontinuity = positionDiscontinuity;
|
this.positionDiscontinuity = positionDiscontinuity;
|
||||||
this.positionDiscontinuityReason = positionDiscontinuityReason;
|
this.positionDiscontinuityReason = positionDiscontinuityReason;
|
||||||
this.timelineChangeReason = timelineChangeReason;
|
this.timelineChangeReason = timelineChangeReason;
|
||||||
|
this.mediaItemTransitioned = mediaItemTransitioned;
|
||||||
|
this.mediaItemTransitionReason = mediaItemTransitionReason;
|
||||||
|
this.mediaItem = mediaItem;
|
||||||
this.playWhenReadyChangeReason = playWhenReadyChangeReason;
|
this.playWhenReadyChangeReason = playWhenReadyChangeReason;
|
||||||
this.seekProcessed = seekProcessed;
|
this.seekProcessed = seekProcessed;
|
||||||
playbackStateChanged = previousPlaybackInfo.playbackState != playbackInfo.playbackState;
|
playbackStateChanged = previousPlaybackInfo.playbackState != playbackInfo.playbackState;
|
||||||
|
|
@ -1444,6 +1517,11 @@ import java.util.concurrent.TimeoutException;
|
||||||
listenerSnapshot,
|
listenerSnapshot,
|
||||||
listener -> listener.onPositionDiscontinuity(positionDiscontinuityReason));
|
listener -> listener.onPositionDiscontinuity(positionDiscontinuityReason));
|
||||||
}
|
}
|
||||||
|
if (mediaItemTransitioned) {
|
||||||
|
invokeAll(
|
||||||
|
listenerSnapshot,
|
||||||
|
listener -> listener.onMediaItemTransition(mediaItem, mediaItemTransitionReason));
|
||||||
|
}
|
||||||
if (playbackErrorChanged) {
|
if (playbackErrorChanged) {
|
||||||
invokeAll(listenerSnapshot, listener -> listener.onPlayerError(playbackInfo.playbackError));
|
invokeAll(listenerSnapshot, listener -> listener.onPlayerError(playbackInfo.playbackError));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -470,6 +470,15 @@ public interface Player {
|
||||||
default void onTimelineChanged(
|
default void onTimelineChanged(
|
||||||
Timeline timeline, @Nullable Object manifest, @TimelineChangeReason int reason) {}
|
Timeline timeline, @Nullable Object manifest, @TimelineChangeReason int reason) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when playback transitions to a different media item.
|
||||||
|
*
|
||||||
|
* @param mediaItem The {@link MediaItem}. May be null if the timeline becomes empty.
|
||||||
|
* @param reason The reason for the transition.
|
||||||
|
*/
|
||||||
|
default void onMediaItemTransition(
|
||||||
|
@Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the available or selected tracks change.
|
* Called when the available or selected tracks change.
|
||||||
*
|
*
|
||||||
|
|
@ -766,6 +775,32 @@ public interface Player {
|
||||||
/** Timeline changed as a result of a dynamic update introduced by the played media. */
|
/** Timeline changed as a result of a dynamic update introduced by the played media. */
|
||||||
int TIMELINE_CHANGE_REASON_SOURCE_UPDATE = 1;
|
int TIMELINE_CHANGE_REASON_SOURCE_UPDATE = 1;
|
||||||
|
|
||||||
|
/** Reasons for media item transitions. */
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@IntDef({
|
||||||
|
MEDIA_ITEM_TRANSITION_REASON_REPEAT,
|
||||||
|
MEDIA_ITEM_TRANSITION_REASON_AUTO,
|
||||||
|
MEDIA_ITEM_TRANSITION_REASON_SEEK,
|
||||||
|
MEDIA_ITEM_TRANSITION_REASON_SKIP,
|
||||||
|
MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED
|
||||||
|
})
|
||||||
|
@interface MediaItemTransitionReason {}
|
||||||
|
/** The media item has been repeated. */
|
||||||
|
int MEDIA_ITEM_TRANSITION_REASON_REPEAT = 0;
|
||||||
|
/** Playback has automatically transitioned to the next media item. */
|
||||||
|
int MEDIA_ITEM_TRANSITION_REASON_AUTO = 1;
|
||||||
|
/** A seek to another media item has occurred. */
|
||||||
|
int MEDIA_ITEM_TRANSITION_REASON_SEEK = 2;
|
||||||
|
/** Playback skipped to a new media item (for example after failure). */
|
||||||
|
int MEDIA_ITEM_TRANSITION_REASON_SKIP = 3;
|
||||||
|
/**
|
||||||
|
* The current media item has changed because of a modification of the timeline. This can either
|
||||||
|
* be if the period previously being played has been removed, or when the timeline becomes
|
||||||
|
* non-empty after being empty.
|
||||||
|
*/
|
||||||
|
int MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED = 4;
|
||||||
|
|
||||||
/** The default playback speed. */
|
/** The default playback speed. */
|
||||||
float DEFAULT_PLAYBACK_SPEED = 1.0f;
|
float DEFAULT_PLAYBACK_SPEED = 1.0f;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
|
import com.google.android.exoplayer2.MediaItem;
|
||||||
import com.google.android.exoplayer2.PlaybackParameters;
|
import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.Player.PlaybackSuppressionReason;
|
import com.google.android.exoplayer2.Player.PlaybackSuppressionReason;
|
||||||
|
|
@ -455,6 +456,15 @@ public class AnalyticsCollector
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void onMediaItemTransition(
|
||||||
|
@Nullable MediaItem mediaItem, @Player.MediaItemTransitionReason int reason) {
|
||||||
|
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||||
|
for (AnalyticsListener listener : listeners) {
|
||||||
|
listener.onMediaItemTransition(eventTime, mediaItem, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void onTracksChanged(
|
public final void onTracksChanged(
|
||||||
TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
|
import com.google.android.exoplayer2.MediaItem;
|
||||||
import com.google.android.exoplayer2.PlaybackParameters;
|
import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.Player.DiscontinuityReason;
|
import com.google.android.exoplayer2.Player.DiscontinuityReason;
|
||||||
|
|
@ -207,6 +208,18 @@ public interface AnalyticsListener {
|
||||||
*/
|
*/
|
||||||
default void onTimelineChanged(EventTime eventTime, @TimelineChangeReason int reason) {}
|
default void onTimelineChanged(EventTime eventTime, @TimelineChangeReason int reason) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when playback transitions to a different media item.
|
||||||
|
*
|
||||||
|
* @param eventTime The event time.
|
||||||
|
* @param mediaItem The media item.
|
||||||
|
* @param reason The reason for the media item transition.
|
||||||
|
*/
|
||||||
|
default void onMediaItemTransition(
|
||||||
|
EventTime eventTime,
|
||||||
|
@Nullable MediaItem mediaItem,
|
||||||
|
@Player.MediaItemTransitionReason int reason) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a position discontinuity occurred.
|
* Called when a position discontinuity occurred.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
|
import com.google.android.exoplayer2.MediaItem;
|
||||||
import com.google.android.exoplayer2.PlaybackParameters;
|
import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.Player.PlaybackSuppressionReason;
|
import com.google.android.exoplayer2.Player.PlaybackSuppressionReason;
|
||||||
|
|
@ -196,6 +197,19 @@ public class EventLogger implements AnalyticsListener {
|
||||||
logd("]");
|
logd("]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMediaItemTransition(
|
||||||
|
EventTime eventTime, @Nullable MediaItem mediaItem, int reason) {
|
||||||
|
logd(
|
||||||
|
"mediaItem ["
|
||||||
|
+ getEventTimeString(eventTime)
|
||||||
|
+ ", "
|
||||||
|
+ (mediaItem == null ? "null" : "mediaId=" + mediaItem.mediaId)
|
||||||
|
+ ", reason="
|
||||||
|
+ getMediaItemTransitionReasonString(reason)
|
||||||
|
+ "]");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlayerError(EventTime eventTime, ExoPlaybackException e) {
|
public void onPlayerError(EventTime eventTime, ExoPlaybackException e) {
|
||||||
loge(eventTime, "playerFailed", e);
|
loge(eventTime, "playerFailed", e);
|
||||||
|
|
@ -648,6 +662,24 @@ public class EventLogger implements AnalyticsListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getMediaItemTransitionReasonString(
|
||||||
|
@Player.MediaItemTransitionReason int reason) {
|
||||||
|
switch (reason) {
|
||||||
|
case Player.MEDIA_ITEM_TRANSITION_REASON_AUTO:
|
||||||
|
return "AUTO";
|
||||||
|
case Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED:
|
||||||
|
return "PLAYLIST_CHANGED";
|
||||||
|
case Player.MEDIA_ITEM_TRANSITION_REASON_REPEAT:
|
||||||
|
return "REPEAT";
|
||||||
|
case Player.MEDIA_ITEM_TRANSITION_REASON_SEEK:
|
||||||
|
return "SEEK";
|
||||||
|
case Player.MEDIA_ITEM_TRANSITION_REASON_SKIP:
|
||||||
|
return "SKIP";
|
||||||
|
default:
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static String getPlaybackSuppressionReasonString(
|
private static String getPlaybackSuppressionReasonString(
|
||||||
@PlaybackSuppressionReason int playbackSuppressionReason) {
|
@PlaybackSuppressionReason int playbackSuppressionReason) {
|
||||||
switch (playbackSuppressionReason) {
|
switch (playbackSuppressionReason) {
|
||||||
|
|
|
||||||
|
|
@ -7886,6 +7886,329 @@ public final class ExoPlayerTest {
|
||||||
assertThat(initialMediaItems).containsExactlyElementsIn(currentMediaItems);
|
assertThat(initialMediaItems).containsExactlyElementsIn(currentMediaItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setMediaSources_notifiesMediaItemTransition() throws Exception {
|
||||||
|
SilenceMediaSource.Factory factory =
|
||||||
|
new SilenceMediaSource.Factory().setDurationUs(C.msToUs(100_000));
|
||||||
|
SilenceMediaSource mediaSource = factory.setTag("1").createMediaSource();
|
||||||
|
|
||||||
|
ExoPlayerTestRunner exoPlayerTestRunner =
|
||||||
|
new ExoPlayerTestRunner.Builder(context)
|
||||||
|
.setMediaSources(mediaSource)
|
||||||
|
.build()
|
||||||
|
.start()
|
||||||
|
.blockUntilEnded(TIMEOUT_MS);
|
||||||
|
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionedSame(mediaSource.getMediaItem());
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionReasonsEqual(
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setMediaSources_replaceWithSameMediaItem_notifiesMediaItemTransition()
|
||||||
|
throws Exception {
|
||||||
|
SilenceMediaSource.Factory factory =
|
||||||
|
new SilenceMediaSource.Factory().setDurationUs(C.msToUs(100_000));
|
||||||
|
SilenceMediaSource mediaSource = factory.setTag("1").createMediaSource();
|
||||||
|
ActionSchedule actionSchedule =
|
||||||
|
new ActionSchedule.Builder(TAG)
|
||||||
|
.waitForPlaybackState(Player.STATE_READY)
|
||||||
|
.setMediaSources(mediaSource)
|
||||||
|
.waitForPlaybackState(Player.STATE_READY)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ExoPlayerTestRunner exoPlayerTestRunner =
|
||||||
|
new ExoPlayerTestRunner.Builder(context)
|
||||||
|
.setMediaSources(mediaSource)
|
||||||
|
.setActionSchedule(actionSchedule)
|
||||||
|
.build()
|
||||||
|
.start()
|
||||||
|
.blockUntilActionScheduleFinished(TIMEOUT_MS)
|
||||||
|
.blockUntilEnded(TIMEOUT_MS);
|
||||||
|
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionedSame(
|
||||||
|
mediaSource.getMediaItem(), mediaSource.getMediaItem());
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionReasonsEqual(
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED,
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void automaticWindowTransition_notifiesMediaItemTransition() throws Exception {
|
||||||
|
SilenceMediaSource.Factory factory =
|
||||||
|
new SilenceMediaSource.Factory().setDurationUs(C.msToUs(100_000));
|
||||||
|
SilenceMediaSource mediaSource1 = factory.setTag("1").createMediaSource();
|
||||||
|
SilenceMediaSource mediaSource2 = factory.setTag("2").createMediaSource();
|
||||||
|
|
||||||
|
ExoPlayerTestRunner exoPlayerTestRunner =
|
||||||
|
new ExoPlayerTestRunner.Builder(context)
|
||||||
|
.setMediaSources(mediaSource1, mediaSource2)
|
||||||
|
.build()
|
||||||
|
.start()
|
||||||
|
.blockUntilEnded(TIMEOUT_MS);
|
||||||
|
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionedSame(
|
||||||
|
mediaSource1.getMediaItem(), mediaSource2.getMediaItem());
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionReasonsEqual(
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED,
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_AUTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clearMediaItem_notifiesMediaItemTransition() throws Exception {
|
||||||
|
SilenceMediaSource.Factory factory =
|
||||||
|
new SilenceMediaSource.Factory().setDurationUs(C.msToUs(100_000));
|
||||||
|
SilenceMediaSource mediaSource1 = factory.setTag("1").createMediaSource();
|
||||||
|
SilenceMediaSource mediaSource2 = factory.setTag("2").createMediaSource();
|
||||||
|
ActionSchedule actionSchedule =
|
||||||
|
new ActionSchedule.Builder(TAG)
|
||||||
|
.waitForPlaybackState(Player.STATE_READY)
|
||||||
|
.playUntilPosition(/* windowIndex= */ 1, /* positionMs= */ 2000)
|
||||||
|
.clearMediaItems()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ExoPlayerTestRunner exoPlayerTestRunner =
|
||||||
|
new ExoPlayerTestRunner.Builder(context)
|
||||||
|
.setMediaSources(mediaSource1, mediaSource2)
|
||||||
|
.setActionSchedule(actionSchedule)
|
||||||
|
.build()
|
||||||
|
.start()
|
||||||
|
.blockUntilActionScheduleFinished(TIMEOUT_MS)
|
||||||
|
.blockUntilEnded(TIMEOUT_MS);
|
||||||
|
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionedSame(
|
||||||
|
mediaSource1.getMediaItem(), mediaSource2.getMediaItem(), null);
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionReasonsEqual(
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED,
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_AUTO,
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void seekTo_otherWindow_notifiesMediaItemTransition() throws Exception {
|
||||||
|
SilenceMediaSource.Factory factory =
|
||||||
|
new SilenceMediaSource.Factory().setDurationUs(C.msToUs(100_000));
|
||||||
|
SilenceMediaSource mediaSource1 = factory.setTag("1").createMediaSource();
|
||||||
|
SilenceMediaSource mediaSource2 = factory.setTag("2").createMediaSource();
|
||||||
|
ActionSchedule actionSchedule =
|
||||||
|
new ActionSchedule.Builder(TAG)
|
||||||
|
.waitForPlaybackState(Player.STATE_READY)
|
||||||
|
.seek(/* windowIndex= */ 1, /* positionMs= */ 2000)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ExoPlayerTestRunner exoPlayerTestRunner =
|
||||||
|
new ExoPlayerTestRunner.Builder(context)
|
||||||
|
.setMediaSources(mediaSource1, mediaSource2)
|
||||||
|
.setActionSchedule(actionSchedule)
|
||||||
|
.build()
|
||||||
|
.start()
|
||||||
|
.blockUntilActionScheduleFinished(TIMEOUT_MS)
|
||||||
|
.blockUntilEnded(TIMEOUT_MS);
|
||||||
|
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionedSame(
|
||||||
|
mediaSource1.getMediaItem(), mediaSource2.getMediaItem());
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionReasonsEqual(
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED,
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_SEEK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void seekTo_sameWindow_doesNotNotifyMediaItemTransition() throws Exception {
|
||||||
|
SilenceMediaSource.Factory factory =
|
||||||
|
new SilenceMediaSource.Factory().setDurationUs(C.msToUs(100_000));
|
||||||
|
SilenceMediaSource mediaSource1 = factory.setTag("1").createMediaSource();
|
||||||
|
SilenceMediaSource mediaSource2 = factory.setTag("2").createMediaSource();
|
||||||
|
ActionSchedule actionSchedule =
|
||||||
|
new ActionSchedule.Builder(TAG)
|
||||||
|
.pause()
|
||||||
|
.waitForPlaybackState(Player.STATE_READY)
|
||||||
|
.playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 2000)
|
||||||
|
.seek(/* windowIndex= */ 0, /* positionMs= */ 20_000)
|
||||||
|
.stop()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ExoPlayerTestRunner exoPlayerTestRunner =
|
||||||
|
new ExoPlayerTestRunner.Builder(context)
|
||||||
|
.setMediaSources(mediaSource1, mediaSource2)
|
||||||
|
.setActionSchedule(actionSchedule)
|
||||||
|
.build()
|
||||||
|
.start()
|
||||||
|
.blockUntilActionScheduleFinished(TIMEOUT_MS)
|
||||||
|
.blockUntilEnded(TIMEOUT_MS);
|
||||||
|
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionedSame(mediaSource1.getMediaItem());
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionReasonsEqual(
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void repeat_notifiesMediaItemTransition() throws Exception {
|
||||||
|
SilenceMediaSource.Factory factory =
|
||||||
|
new SilenceMediaSource.Factory().setDurationUs(C.msToUs(100_000));
|
||||||
|
SilenceMediaSource mediaSource1 = factory.setTag("1").createMediaSource();
|
||||||
|
SilenceMediaSource mediaSource2 = factory.setTag("2").createMediaSource();
|
||||||
|
ActionSchedule actionSchedule =
|
||||||
|
new ActionSchedule.Builder(TAG)
|
||||||
|
.pause()
|
||||||
|
.waitForPlaybackState(Player.STATE_READY)
|
||||||
|
.executeRunnable(
|
||||||
|
new PlayerRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run(SimpleExoPlayer player) {
|
||||||
|
player.setRepeatMode(Player.REPEAT_MODE_ONE);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.play()
|
||||||
|
.waitForPositionDiscontinuity()
|
||||||
|
.waitForPositionDiscontinuity()
|
||||||
|
.executeRunnable(
|
||||||
|
new PlayerRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run(SimpleExoPlayer player) {
|
||||||
|
player.setRepeatMode(Player.REPEAT_MODE_OFF);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ExoPlayerTestRunner exoPlayerTestRunner =
|
||||||
|
new ExoPlayerTestRunner.Builder(context)
|
||||||
|
.setMediaSources(mediaSource1, mediaSource2)
|
||||||
|
.setActionSchedule(actionSchedule)
|
||||||
|
.build()
|
||||||
|
.start()
|
||||||
|
.blockUntilActionScheduleFinished(TIMEOUT_MS)
|
||||||
|
.blockUntilEnded(TIMEOUT_MS);
|
||||||
|
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionedSame(
|
||||||
|
mediaSource1.getMediaItem(),
|
||||||
|
mediaSource1.getMediaItem(),
|
||||||
|
mediaSource1.getMediaItem(),
|
||||||
|
mediaSource2.getMediaItem());
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionReasonsEqual(
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED,
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_REPEAT,
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_REPEAT,
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_AUTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void stop_withReset_notifiesMediaItemTransition() throws Exception {
|
||||||
|
SilenceMediaSource.Factory factory =
|
||||||
|
new SilenceMediaSource.Factory().setDurationUs(C.msToUs(100_000));
|
||||||
|
SilenceMediaSource mediaSource1 = factory.setTag("1").createMediaSource();
|
||||||
|
SilenceMediaSource mediaSource2 = factory.setTag("2").createMediaSource();
|
||||||
|
ActionSchedule actionSchedule =
|
||||||
|
new ActionSchedule.Builder(TAG)
|
||||||
|
.pause()
|
||||||
|
.waitForPlaybackState(Player.STATE_READY)
|
||||||
|
.playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 2000)
|
||||||
|
.stop(/* reset= */ true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ExoPlayerTestRunner exoPlayerTestRunner =
|
||||||
|
new ExoPlayerTestRunner.Builder(context)
|
||||||
|
.setMediaSources(mediaSource1, mediaSource2)
|
||||||
|
.setActionSchedule(actionSchedule)
|
||||||
|
.build()
|
||||||
|
.start()
|
||||||
|
.blockUntilActionScheduleFinished(TIMEOUT_MS)
|
||||||
|
.blockUntilEnded(TIMEOUT_MS);
|
||||||
|
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionedSame(mediaSource1.getMediaItem(), null);
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionReasonsEqual(
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED,
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void stop_withoutReset_doesNotNotifyMediaItemTransition() throws Exception {
|
||||||
|
SilenceMediaSource.Factory factory =
|
||||||
|
new SilenceMediaSource.Factory().setDurationUs(C.msToUs(100_000));
|
||||||
|
SilenceMediaSource mediaSource1 = factory.setTag("1").createMediaSource();
|
||||||
|
SilenceMediaSource mediaSource2 = factory.setTag("2").createMediaSource();
|
||||||
|
ActionSchedule actionSchedule =
|
||||||
|
new ActionSchedule.Builder(TAG)
|
||||||
|
.pause()
|
||||||
|
.waitForPlaybackState(Player.STATE_READY)
|
||||||
|
.playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 2000)
|
||||||
|
.stop(/* reset= */ false)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ExoPlayerTestRunner exoPlayerTestRunner =
|
||||||
|
new ExoPlayerTestRunner.Builder(context)
|
||||||
|
.setMediaSources(mediaSource1, mediaSource2)
|
||||||
|
.setActionSchedule(actionSchedule)
|
||||||
|
.build()
|
||||||
|
.start()
|
||||||
|
.blockUntilActionScheduleFinished(TIMEOUT_MS)
|
||||||
|
.blockUntilEnded(TIMEOUT_MS);
|
||||||
|
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionedSame(mediaSource1.getMediaItem());
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionReasonsEqual(
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void timelineRefresh_withModifiedMediaItem_doesNotNotifyMediaItemTransition()
|
||||||
|
throws Exception {
|
||||||
|
MediaItem initialMediaItem = FakeTimeline.FAKE_MEDIA_ITEM.buildUpon().setTag(0).build();
|
||||||
|
TimelineWindowDefinition initialWindow =
|
||||||
|
new TimelineWindowDefinition(
|
||||||
|
/* periodCount= */ 1,
|
||||||
|
/* id= */ 0,
|
||||||
|
/* isSeekable= */ true,
|
||||||
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false,
|
||||||
|
/* isPlaceholder= */ false,
|
||||||
|
/* durationUs= */ 10_000_000,
|
||||||
|
/* defaultPositionUs= */ 0,
|
||||||
|
/* windowOffsetInFirstPeriodUs= */ 0,
|
||||||
|
AdPlaybackState.NONE,
|
||||||
|
initialMediaItem);
|
||||||
|
TimelineWindowDefinition secondWindow =
|
||||||
|
new TimelineWindowDefinition(
|
||||||
|
/* periodCount= */ 1,
|
||||||
|
/* id= */ 0,
|
||||||
|
/* isSeekable= */ true,
|
||||||
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false,
|
||||||
|
/* isPlaceholder= */ false,
|
||||||
|
/* durationUs= */ 10_000_000,
|
||||||
|
/* defaultPositionUs= */ 0,
|
||||||
|
/* windowOffsetInFirstPeriodUs= */ 0,
|
||||||
|
AdPlaybackState.NONE,
|
||||||
|
initialMediaItem.buildUpon().setTag(1).build());
|
||||||
|
FakeTimeline timeline = new FakeTimeline(initialWindow);
|
||||||
|
FakeTimeline newTimeline = new FakeTimeline(secondWindow);
|
||||||
|
FakeMediaSource mediaSource = new FakeMediaSource(timeline);
|
||||||
|
ActionSchedule actionSchedule =
|
||||||
|
new ActionSchedule.Builder(TAG)
|
||||||
|
.pause()
|
||||||
|
.waitForPlaybackState(Player.STATE_READY)
|
||||||
|
.playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 2000)
|
||||||
|
.waitForPlayWhenReady(false)
|
||||||
|
.executeRunnable(
|
||||||
|
() -> {
|
||||||
|
mediaSource.setNewSourceInfo(newTimeline);
|
||||||
|
})
|
||||||
|
.play()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ExoPlayerTestRunner exoPlayerTestRunner =
|
||||||
|
new ExoPlayerTestRunner.Builder(context)
|
||||||
|
.setMediaSources(mediaSource)
|
||||||
|
.setActionSchedule(actionSchedule)
|
||||||
|
.build()
|
||||||
|
.start()
|
||||||
|
.blockUntilActionScheduleFinished(TIMEOUT_MS)
|
||||||
|
.blockUntilEnded(TIMEOUT_MS);
|
||||||
|
|
||||||
|
exoPlayerTestRunner.assertTimelinesSame(placeholderTimeline, timeline, newTimeline);
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionReasonsEqual(
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED);
|
||||||
|
exoPlayerTestRunner.assertMediaItemsTransitionedSame(initialMediaItem);
|
||||||
|
}
|
||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
private static ActionSchedule.Builder addSurfaceSwitch(ActionSchedule.Builder builder) {
|
private static ActionSchedule.Builder addSurfaceSwitch(ActionSchedule.Builder builder) {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.LoadControl;
|
import com.google.android.exoplayer2.LoadControl;
|
||||||
|
import com.google.android.exoplayer2.MediaItem;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.Renderer;
|
import com.google.android.exoplayer2.Renderer;
|
||||||
import com.google.android.exoplayer2.RenderersFactory;
|
import com.google.android.exoplayer2.RenderersFactory;
|
||||||
|
|
@ -356,6 +357,8 @@ public final class ExoPlayerTestRunner implements Player.EventListener, ActionSc
|
||||||
private final CountDownLatch actionScheduleFinishedCountDownLatch;
|
private final CountDownLatch actionScheduleFinishedCountDownLatch;
|
||||||
private final ArrayList<Timeline> timelines;
|
private final ArrayList<Timeline> timelines;
|
||||||
private final ArrayList<Integer> timelineChangeReasons;
|
private final ArrayList<Integer> timelineChangeReasons;
|
||||||
|
private final ArrayList<MediaItem> mediaItems;
|
||||||
|
private final ArrayList<Integer> mediaItemTransitionReasons;
|
||||||
private final ArrayList<Integer> periodIndices;
|
private final ArrayList<Integer> periodIndices;
|
||||||
private final ArrayList<Integer> discontinuityReasons;
|
private final ArrayList<Integer> discontinuityReasons;
|
||||||
private final ArrayList<Integer> playbackStates;
|
private final ArrayList<Integer> playbackStates;
|
||||||
|
|
@ -387,6 +390,8 @@ public final class ExoPlayerTestRunner implements Player.EventListener, ActionSc
|
||||||
this.analyticsListener = analyticsListener;
|
this.analyticsListener = analyticsListener;
|
||||||
timelines = new ArrayList<>();
|
timelines = new ArrayList<>();
|
||||||
timelineChangeReasons = new ArrayList<>();
|
timelineChangeReasons = new ArrayList<>();
|
||||||
|
mediaItems = new ArrayList<>();
|
||||||
|
mediaItemTransitionReasons = new ArrayList<>();
|
||||||
periodIndices = new ArrayList<>();
|
periodIndices = new ArrayList<>();
|
||||||
discontinuityReasons = new ArrayList<>();
|
discontinuityReasons = new ArrayList<>();
|
||||||
playbackStates = new ArrayList<>();
|
playbackStates = new ArrayList<>();
|
||||||
|
|
@ -525,12 +530,34 @@ public final class ExoPlayerTestRunner implements Player.EventListener, ActionSc
|
||||||
assertThat(timelineChangeReasons).containsExactlyElementsIn(Arrays.asList(reasons)).inOrder();
|
assertThat(timelineChangeReasons).containsExactlyElementsIn(Arrays.asList(reasons)).inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the media items reported by {@link
|
||||||
|
* Player.EventListener#onMediaItemTransition(MediaItem, int)} are the same as the provided media
|
||||||
|
* items.
|
||||||
|
*
|
||||||
|
* @param mediaItems A list of expected {@link MediaItem media items}.
|
||||||
|
*/
|
||||||
|
public void assertMediaItemsTransitionedSame(MediaItem... mediaItems) {
|
||||||
|
assertThat(this.mediaItems).containsExactlyElementsIn(mediaItems).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the media item transition reasons reported by {@link
|
||||||
|
* Player.EventListener#onMediaItemTransition(MediaItem, int)} are the same as the provided
|
||||||
|
* reasons.
|
||||||
|
*
|
||||||
|
* @param reasons A list of expected transition reasons.
|
||||||
|
*/
|
||||||
|
public void assertMediaItemsTransitionReasonsEqual(Integer... reasons) {
|
||||||
|
assertThat(this.mediaItemTransitionReasons).containsExactlyElementsIn(reasons).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that the playback states reported by {@link
|
* Asserts that the playback states reported by {@link
|
||||||
* Player.EventListener#onPlaybackStateChanged(int)} are equal to the provided playback states.
|
* Player.EventListener#onPlaybackStateChanged(int)} are equal to the provided playback states.
|
||||||
*/
|
*/
|
||||||
public void assertPlaybackStatesEqual(Integer... states) {
|
public void assertPlaybackStatesEqual(Integer... states) {
|
||||||
assertThat(playbackStates).containsExactlyElementsIn(Arrays.asList(states)).inOrder();
|
assertThat(playbackStates).containsExactlyElementsIn(states).inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -617,6 +644,13 @@ public final class ExoPlayerTestRunner implements Player.EventListener, ActionSc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMediaItemTransition(
|
||||||
|
@Nullable MediaItem mediaItem, @Player.MediaItemTransitionReason int reason) {
|
||||||
|
mediaItems.add(mediaItem);
|
||||||
|
mediaItemTransitionReasons.add(reason);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
||||||
this.trackGroups = trackGroups;
|
this.trackGroups = trackGroups;
|
||||||
|
|
|
||||||
|
|
@ -166,10 +166,53 @@ public final class FakeTimeline extends Timeline {
|
||||||
long defaultPositionUs,
|
long defaultPositionUs,
|
||||||
long windowOffsetInFirstPeriodUs,
|
long windowOffsetInFirstPeriodUs,
|
||||||
AdPlaybackState adPlaybackState) {
|
AdPlaybackState adPlaybackState) {
|
||||||
|
this(
|
||||||
|
periodCount,
|
||||||
|
id,
|
||||||
|
isSeekable,
|
||||||
|
isDynamic,
|
||||||
|
isLive,
|
||||||
|
isPlaceholder,
|
||||||
|
durationUs,
|
||||||
|
defaultPositionUs,
|
||||||
|
windowOffsetInFirstPeriodUs,
|
||||||
|
adPlaybackState,
|
||||||
|
FAKE_MEDIA_ITEM.buildUpon().setTag(id).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a window definition with ad groups and a custom media item.
|
||||||
|
*
|
||||||
|
* @param periodCount The number of periods in the window. Each period get an equal slice of the
|
||||||
|
* total window duration.
|
||||||
|
* @param id The UID of the window.
|
||||||
|
* @param isSeekable Whether the window is seekable.
|
||||||
|
* @param isDynamic Whether the window is dynamic.
|
||||||
|
* @param isLive Whether the window is live.
|
||||||
|
* @param isPlaceholder Whether the window is a placeholder.
|
||||||
|
* @param durationUs The duration of the window in microseconds.
|
||||||
|
* @param defaultPositionUs The default position of the window in microseconds.
|
||||||
|
* @param windowOffsetInFirstPeriodUs The offset of the window in the first period, in
|
||||||
|
* microseconds.
|
||||||
|
* @param adPlaybackState The ad playback state.
|
||||||
|
* @param mediaItem The media item to include in the timeline.
|
||||||
|
*/
|
||||||
|
public TimelineWindowDefinition(
|
||||||
|
int periodCount,
|
||||||
|
Object id,
|
||||||
|
boolean isSeekable,
|
||||||
|
boolean isDynamic,
|
||||||
|
boolean isLive,
|
||||||
|
boolean isPlaceholder,
|
||||||
|
long durationUs,
|
||||||
|
long defaultPositionUs,
|
||||||
|
long windowOffsetInFirstPeriodUs,
|
||||||
|
AdPlaybackState adPlaybackState,
|
||||||
|
MediaItem mediaItem) {
|
||||||
Assertions.checkArgument(durationUs != C.TIME_UNSET || periodCount == 1);
|
Assertions.checkArgument(durationUs != C.TIME_UNSET || periodCount == 1);
|
||||||
this.periodCount = periodCount;
|
this.periodCount = periodCount;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.mediaItem = FAKE_MEDIA_ITEM.buildUpon().setTag(id).build();
|
this.mediaItem = mediaItem;
|
||||||
this.isSeekable = isSeekable;
|
this.isSeekable = isSeekable;
|
||||||
this.isDynamic = isDynamic;
|
this.isDynamic = isDynamic;
|
||||||
this.isLive = isLive;
|
this.isLive = isLive;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue