Commit 4c33c511 by bachinger Committed by marcbaechinger

Call new onPositionDiscontinuity callback in CastPlayer

PiperOrigin-RevId: 367020270
parent 6f4db96d
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.ext.cast; package com.google.android.exoplayer2.ext.cast;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min; import static java.lang.Math.min;
import android.os.Looper; import android.os.Looper;
...@@ -39,6 +40,7 @@ import com.google.android.exoplayer2.util.Clock; ...@@ -39,6 +40,7 @@ import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.ListenerSet; import com.google.android.exoplayer2.util.ListenerSet;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import com.google.android.gms.cast.CastStatusCodes; import com.google.android.gms.cast.CastStatusCodes;
import com.google.android.gms.cast.MediaInfo; import com.google.android.gms.cast.MediaInfo;
import com.google.android.gms.cast.MediaQueueItem; import com.google.android.gms.cast.MediaQueueItem;
...@@ -129,6 +131,7 @@ public final class CastPlayer extends BasePlayer { ...@@ -129,6 +131,7 @@ public final class CastPlayer extends BasePlayer {
private int pendingSeekCount; private int pendingSeekCount;
private int pendingSeekWindowIndex; private int pendingSeekWindowIndex;
private long pendingSeekPositionMs; private long pendingSeekPositionMs;
@Nullable private PositionInfo pendingMediaItemRemovalPosition;
/** /**
* Creates a new cast player that uses a {@link DefaultMediaItemConverter}. * Creates a new cast player that uses a {@link DefaultMediaItemConverter}.
...@@ -460,23 +463,29 @@ public final class CastPlayer extends BasePlayer { ...@@ -460,23 +463,29 @@ public final class CastPlayer extends BasePlayer {
if (getCurrentWindowIndex() != windowIndex) { if (getCurrentWindowIndex() != windowIndex) {
remoteMediaClient.queueJumpToItem((int) currentTimeline.getPeriod(windowIndex, period).uid, remoteMediaClient.queueJumpToItem((int) currentTimeline.getPeriod(windowIndex, period).uid,
positionMs, null).setResultCallback(seekResultCallback); positionMs, null).setResultCallback(seekResultCallback);
// TODO(internal b/182261884): queue `onMediaItemTransition` event when the media item is
// repeated.
MediaItem mediaItem = currentTimeline.getWindow(windowIndex, window).mediaItem;
listeners.queueEvent(
Player.EVENT_MEDIA_ITEM_TRANSITION,
listener ->
listener.onMediaItemTransition(mediaItem, MEDIA_ITEM_TRANSITION_REASON_SEEK));
} else { } else {
remoteMediaClient.seek(positionMs).setResultCallback(seekResultCallback); remoteMediaClient.seek(positionMs).setResultCallback(seekResultCallback);
} }
PositionInfo oldPosition = getCurrentPositionInfo();
pendingSeekCount++; pendingSeekCount++;
pendingSeekWindowIndex = windowIndex; pendingSeekWindowIndex = windowIndex;
pendingSeekPositionMs = positionMs; pendingSeekPositionMs = positionMs;
// TODO(b/181262841): call new onPositionDiscontinuity callback PositionInfo newPosition = getCurrentPositionInfo();
listeners.queueEvent( listeners.queueEvent(
Player.EVENT_POSITION_DISCONTINUITY, Player.EVENT_POSITION_DISCONTINUITY,
listener -> listener.onPositionDiscontinuity(DISCONTINUITY_REASON_SEEK)); listener -> {
listener.onPositionDiscontinuity(DISCONTINUITY_REASON_SEEK);
listener.onPositionDiscontinuity(oldPosition, newPosition, DISCONTINUITY_REASON_SEEK);
});
if (oldPosition.windowIndex != newPosition.windowIndex) {
// TODO(internal b/182261884): queue `onMediaItemTransition` event when the media item is
// repeated.
MediaItem mediaItem = getCurrentTimeline().getWindow(windowIndex, window).mediaItem;
listeners.queueEvent(
Player.EVENT_MEDIA_ITEM_TRANSITION,
listener ->
listener.onMediaItemTransition(mediaItem, MEDIA_ITEM_TRANSITION_REASON_SEEK));
}
updateAvailableCommandsAndNotifyIfChanged(); updateAvailableCommandsAndNotifyIfChanged();
} else if (pendingSeekCount == 0) { } else if (pendingSeekCount == 0) {
listeners.queueEvent(/* eventFlag= */ C.INDEX_UNSET, EventListener::onSeekProcessed); listeners.queueEvent(/* eventFlag= */ C.INDEX_UNSET, EventListener::onSeekProcessed);
...@@ -657,7 +666,12 @@ public final class CastPlayer extends BasePlayer { ...@@ -657,7 +666,12 @@ public final class CastPlayer extends BasePlayer {
// There is no session. We leave the state of the player as it is now. // There is no session. We leave the state of the player as it is now.
return; return;
} }
int previousWindowIndex = this.currentWindowIndex; int oldWindowIndex = this.currentWindowIndex;
@Nullable
Object oldPeriodUid =
!getCurrentTimeline().isEmpty()
? getCurrentTimeline().getPeriod(oldWindowIndex, period, /* setIds= */ true).uid
: null;
boolean wasPlaying = playbackState == Player.STATE_READY && playWhenReady.value; boolean wasPlaying = playbackState == Player.STATE_READY && playWhenReady.value;
updatePlayerStateAndNotifyIfChanged(/* resultCallback= */ null); updatePlayerStateAndNotifyIfChanged(/* resultCallback= */ null);
boolean isPlaying = playbackState == Player.STATE_READY && playWhenReady.value; boolean isPlaying = playbackState == Player.STATE_READY && playWhenReady.value;
...@@ -667,16 +681,49 @@ public final class CastPlayer extends BasePlayer { ...@@ -667,16 +681,49 @@ public final class CastPlayer extends BasePlayer {
} }
updateRepeatModeAndNotifyIfChanged(/* resultCallback= */ null); updateRepeatModeAndNotifyIfChanged(/* resultCallback= */ null);
boolean playingPeriodChangedByTimelineChange = updateTimelineAndNotifyIfChanged(); boolean playingPeriodChangedByTimelineChange = updateTimelineAndNotifyIfChanged();
Timeline currentTimeline = getCurrentTimeline();
int currentWindowIndex = fetchCurrentWindowIndex(remoteMediaClient, currentTimeline); currentWindowIndex = fetchCurrentWindowIndex(remoteMediaClient, currentTimeline);
@Nullable
Object currentPeriodUid =
!currentTimeline.isEmpty()
? currentTimeline.getPeriod(currentWindowIndex, period, /* setIds= */ true).uid
: null;
if (!playingPeriodChangedByTimelineChange if (!playingPeriodChangedByTimelineChange
&& previousWindowIndex != currentWindowIndex && !Util.areEqual(oldPeriodUid, currentPeriodUid)
&& pendingSeekCount == 0) { && pendingSeekCount == 0) {
this.currentWindowIndex = currentWindowIndex; // Report discontinuity and media item auto transition.
// TODO(b/181262841): call new onPositionDiscontinuity callback currentTimeline.getPeriod(oldWindowIndex, period, /* setIds= */ true);
currentTimeline.getWindow(oldWindowIndex, window);
long windowDurationMs = window.getDurationMs();
PositionInfo oldPosition =
new PositionInfo(
window.uid,
period.windowIndex,
period.uid,
period.windowIndex,
/* positionMs= */ windowDurationMs,
/* contentPositionMs= */ windowDurationMs,
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
currentTimeline.getPeriod(currentWindowIndex, period, /* setIds= */ true);
currentTimeline.getWindow(currentWindowIndex, window);
PositionInfo newPosition =
new PositionInfo(
window.uid,
period.windowIndex,
period.uid,
period.windowIndex,
/* positionMs= */ window.getDefaultPositionMs(),
/* contentPositionMs= */ window.getDefaultPositionMs(),
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
listeners.queueEvent( listeners.queueEvent(
Player.EVENT_POSITION_DISCONTINUITY, Player.EVENT_POSITION_DISCONTINUITY,
listener -> listener.onPositionDiscontinuity(DISCONTINUITY_REASON_AUTO_TRANSITION)); listener -> {
listener.onPositionDiscontinuity(DISCONTINUITY_REASON_AUTO_TRANSITION);
listener.onPositionDiscontinuity(
oldPosition, newPosition, DISCONTINUITY_REASON_AUTO_TRANSITION);
});
listeners.queueEvent( listeners.queueEvent(
Player.EVENT_MEDIA_ITEM_TRANSITION, Player.EVENT_MEDIA_ITEM_TRANSITION,
listener -> listener ->
...@@ -731,13 +778,14 @@ public final class CastPlayer extends BasePlayer { ...@@ -731,13 +778,14 @@ public final class CastPlayer extends BasePlayer {
*/ */
@SuppressWarnings("deprecation") // Calling deprecated listener method. @SuppressWarnings("deprecation") // Calling deprecated listener method.
private boolean updateTimelineAndNotifyIfChanged() { private boolean updateTimelineAndNotifyIfChanged() {
Timeline previousTimeline = currentTimeline; Timeline oldTimeline = currentTimeline;
int previousWindowIndex = currentWindowIndex; int oldWindowIndex = currentWindowIndex;
boolean playingPeriodChanged = false; boolean playingPeriodChanged = false;
if (updateTimeline()) { if (updateTimeline()) {
// TODO: Differentiate TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED and // TODO: Differentiate TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED and
// TIMELINE_CHANGE_REASON_SOURCE_UPDATE [see internal: b/65152553]. // TIMELINE_CHANGE_REASON_SOURCE_UPDATE [see internal: b/65152553].
Timeline timeline = currentTimeline; Timeline timeline = currentTimeline;
// Call onTimelineChanged.
listeners.queueEvent( listeners.queueEvent(
Player.EVENT_TIMELINE_CHANGED, Player.EVENT_TIMELINE_CHANGED,
listener -> { listener -> {
...@@ -746,15 +794,48 @@ public final class CastPlayer extends BasePlayer { ...@@ -746,15 +794,48 @@ public final class CastPlayer extends BasePlayer {
listener.onTimelineChanged(timeline, Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE); listener.onTimelineChanged(timeline, Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE);
}); });
updateAvailableCommandsAndNotifyIfChanged(); // Call onPositionDiscontinuity if required.
Timeline currentTimeline = getCurrentTimeline();
if (currentTimeline.isEmpty() != previousTimeline.isEmpty()) { boolean playingPeriodRemoved = false;
// Timeline initially populated or timeline cleared. if (!oldTimeline.isEmpty()) {
playingPeriodChanged = true; Object oldPeriodUid =
} else if (!currentTimeline.isEmpty()) { castNonNull(oldTimeline.getPeriod(oldWindowIndex, period, /* setIds= */ true).uid);
Object previousWindowUid = previousTimeline.getWindow(previousWindowIndex, window).uid; playingPeriodRemoved = currentTimeline.getIndexOfPeriod(oldPeriodUid) == C.INDEX_UNSET;
playingPeriodChanged = currentTimeline.getIndexOfPeriod(previousWindowUid) == C.INDEX_UNSET; }
if (playingPeriodRemoved) {
PositionInfo oldPosition;
if (pendingMediaItemRemovalPosition != null) {
oldPosition = pendingMediaItemRemovalPosition;
pendingMediaItemRemovalPosition = null;
} else {
// If the media item has been removed by another client, we don't know the removal
// position. We use the current position as a fallback.
oldTimeline.getPeriod(oldWindowIndex, period, /* setIds= */ true);
oldTimeline.getWindow(period.windowIndex, window);
oldPosition =
new PositionInfo(
window.uid,
period.windowIndex,
period.uid,
period.windowIndex,
getCurrentPosition(),
getContentPosition(),
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
}
PositionInfo newPosition = getCurrentPositionInfo();
listeners.queueEvent(
Player.EVENT_POSITION_DISCONTINUITY,
listener -> {
listener.onPositionDiscontinuity(DISCONTINUITY_REASON_REMOVE);
listener.onPositionDiscontinuity(
oldPosition, newPosition, DISCONTINUITY_REASON_REMOVE);
});
} }
// Call onMediaItemTransition if required.
playingPeriodChanged =
currentTimeline.isEmpty() != oldTimeline.isEmpty() || playingPeriodRemoved;
if (playingPeriodChanged) { if (playingPeriodChanged) {
listeners.queueEvent( listeners.queueEvent(
Player.EVENT_MEDIA_ITEM_TRANSITION, Player.EVENT_MEDIA_ITEM_TRANSITION,
...@@ -762,6 +843,7 @@ public final class CastPlayer extends BasePlayer { ...@@ -762,6 +843,7 @@ public final class CastPlayer extends BasePlayer {
listener.onMediaItemTransition( listener.onMediaItemTransition(
getCurrentMediaItem(), MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED)); getCurrentMediaItem(), MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
} }
updateAvailableCommandsAndNotifyIfChanged();
} }
return playingPeriodChanged; return playingPeriodChanged;
} }
...@@ -856,6 +938,10 @@ public final class CastPlayer extends BasePlayer { ...@@ -856,6 +938,10 @@ public final class CastPlayer extends BasePlayer {
startWindowIndex = getCurrentWindowIndex(); startWindowIndex = getCurrentWindowIndex();
startPositionMs = getCurrentPosition(); startPositionMs = getCurrentPosition();
} }
Timeline currentTimeline = getCurrentTimeline();
if (!currentTimeline.isEmpty()) {
pendingMediaItemRemovalPosition = getCurrentPositionInfo();
}
return remoteMediaClient.queueLoad( return remoteMediaClient.queueLoad(
mediaQueueItems, mediaQueueItems,
min(startWindowIndex, mediaQueueItems.length - 1), min(startWindowIndex, mediaQueueItems.length - 1),
...@@ -891,9 +977,41 @@ public final class CastPlayer extends BasePlayer { ...@@ -891,9 +977,41 @@ public final class CastPlayer extends BasePlayer {
if (remoteMediaClient == null || getMediaStatus() == null) { if (remoteMediaClient == null || getMediaStatus() == null) {
return null; return null;
} }
Timeline timeline = getCurrentTimeline();
if (!timeline.isEmpty()) {
Object periodUid =
castNonNull(timeline.getPeriod(getCurrentPeriodIndex(), period, /* setIds= */ true).uid);
for (int uid : uids) {
if (periodUid.equals(uid)) {
pendingMediaItemRemovalPosition = getCurrentPositionInfo();
break;
}
}
}
return remoteMediaClient.queueRemoveItems(uids, /* customData= */ null); return remoteMediaClient.queueRemoveItems(uids, /* customData= */ null);
} }
private PositionInfo getCurrentPositionInfo() {
Timeline currentTimeline = getCurrentTimeline();
@Nullable
Object newPeriodUid =
!currentTimeline.isEmpty()
? currentTimeline.getPeriod(getCurrentPeriodIndex(), period, /* setIds= */ true).uid
: null;
@Nullable
Object newWindowUid =
newPeriodUid != null ? currentTimeline.getWindow(period.windowIndex, window).uid : null;
return new PositionInfo(
newWindowUid,
getCurrentWindowIndex(),
newPeriodUid,
getCurrentPeriodIndex(),
getCurrentPosition(),
getContentPosition(),
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
}
private void setRepeatModeAndNotifyIfChanged(@Player.RepeatMode int repeatMode) { private void setRepeatModeAndNotifyIfChanged(@Player.RepeatMode int repeatMode) {
if (this.repeatMode.value != repeatMode) { if (this.repeatMode.value != repeatMode) {
this.repeatMode.value = repeatMode; this.repeatMode.value = repeatMode;
......
...@@ -36,6 +36,8 @@ import static com.google.android.exoplayer2.Player.COMMAND_SET_SHUFFLE_MODE; ...@@ -36,6 +36,8 @@ import static com.google.android.exoplayer2.Player.COMMAND_SET_SHUFFLE_MODE;
import static com.google.android.exoplayer2.Player.COMMAND_SET_SPEED_AND_PITCH; import static com.google.android.exoplayer2.Player.COMMAND_SET_SPEED_AND_PITCH;
import static com.google.android.exoplayer2.Player.COMMAND_SET_VIDEO_SURFACE; import static com.google.android.exoplayer2.Player.COMMAND_SET_VIDEO_SURFACE;
import static com.google.android.exoplayer2.Player.COMMAND_SET_VOLUME; import static com.google.android.exoplayer2.Player.COMMAND_SET_VOLUME;
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_REMOVE;
import static com.google.android.exoplayer2.Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
...@@ -49,6 +51,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; ...@@ -49,6 +51,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks; import static org.mockito.MockitoAnnotations.initMocks;
import android.net.Uri;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
...@@ -292,6 +295,109 @@ public class CastPlayerTest { ...@@ -292,6 +295,109 @@ public class CastPlayerTest {
assertThat(mediaQueueItems[1].getMedia().getContentId()).isEqualTo(uri2); assertThat(mediaQueueItems[1].getMedia().getContentId()).isEqualTo(uri2);
} }
@SuppressWarnings("deprecation") // Verifies deprecated callback being called correctly.
@Test
public void setMediaItems_replaceExistingPlaylist_notifiesMediaItemTransition() {
List<MediaItem> firstPlaylist = new ArrayList<>();
String uri1 = "http://www.google.com/video1";
String uri2 = "http://www.google.com/video2";
firstPlaylist.add(
new MediaItem.Builder().setUri(uri1).setMimeType(MimeTypes.APPLICATION_MPD).build());
firstPlaylist.add(
new MediaItem.Builder().setUri(uri2).setMimeType(MimeTypes.APPLICATION_MP4).build());
ImmutableList<MediaItem> secondPlaylist =
ImmutableList.of(
new MediaItem.Builder()
.setUri(Uri.EMPTY)
.setMimeType(MimeTypes.APPLICATION_MPD)
.build());
castPlayer.setMediaItems(
firstPlaylist, /* startWindowIndex= */ 1, /* startPositionMs= */ 2000L);
updateTimeLine(
firstPlaylist, /* mediaQueueItemIds= */ new int[] {1, 2}, /* currentItemId= */ 2);
// Replacing existing playlist.
castPlayer.setMediaItems(
secondPlaylist, /* startWindowIndex= */ 0, /* startPositionMs= */ 1000L);
updateTimeLine(secondPlaylist, /* mediaQueueItemIds= */ new int[] {3}, /* currentItemId= */ 3);
InOrder inOrder = Mockito.inOrder(mockListener);
inOrder
.verify(mockListener, times(2))
.onMediaItemTransition(
mediaItemCaptor.capture(), eq(MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
inOrder.verify(mockListener, never()).onMediaItemTransition(any(), anyInt());
assertThat(mediaItemCaptor.getAllValues().get(1).playbackProperties.tag).isEqualTo(3);
}
@SuppressWarnings("deprecation") // Verifies deprecated callback being called correctly.
@Test
public void setMediaItems_replaceExistingPlaylist_notifiesPositionDiscontinuity() {
List<MediaItem> firstPlaylist = new ArrayList<>();
String uri1 = "http://www.google.com/video1";
String uri2 = "http://www.google.com/video2";
firstPlaylist.add(
new MediaItem.Builder().setUri(uri1).setMimeType(MimeTypes.APPLICATION_MPD).build());
firstPlaylist.add(
new MediaItem.Builder().setUri(uri2).setMimeType(MimeTypes.APPLICATION_MP4).build());
ImmutableList<MediaItem> secondPlaylist =
ImmutableList.of(
new MediaItem.Builder()
.setUri(Uri.EMPTY)
.setMimeType(MimeTypes.APPLICATION_MPD)
.build());
castPlayer.setMediaItems(
firstPlaylist, /* startWindowIndex= */ 1, /* startPositionMs= */ 2000L);
updateTimeLine(
firstPlaylist,
/* mediaQueueItemIds= */ new int[] {1, 2},
/* currentItemId= */ 2,
/* streamTypes= */ new int[] {
MediaInfo.STREAM_TYPE_BUFFERED, MediaInfo.STREAM_TYPE_BUFFERED
},
/* durationsMs= */ new long[] {20_000, 20_000},
/* positionMs= */ 2000L);
// Replacing existing playlist.
castPlayer.setMediaItems(
secondPlaylist, /* startWindowIndex= */ 0, /* startPositionMs= */ 1000L);
updateTimeLine(
secondPlaylist,
/* mediaQueueItemIds= */ new int[] {3},
/* currentItemId= */ 3,
/* streamTypes= */ new int[] {MediaInfo.STREAM_TYPE_BUFFERED},
/* durationsMs= */ new long[] {20_000},
/* positionMs= */ 1000L);
Player.PositionInfo oldPosition =
new Player.PositionInfo(
/* windowUid= */ 2,
/* windowIndex= */ 1,
/* periodUid= */ 2,
/* periodIndex= */ 1,
/* positionMs= */ 2000,
/* contentPositionMs= */ 2000,
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
Player.PositionInfo newPosition =
new Player.PositionInfo(
/* windowUid= */ 3,
/* windowIndex= */ 0,
/* periodUid= */ 3,
/* periodIndex= */ 0,
/* positionMs= */ 1000,
/* contentPositionMs= */ 1000,
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
InOrder inOrder = Mockito.inOrder(mockListener);
inOrder.verify(mockListener).onPositionDiscontinuity(eq(DISCONTINUITY_REASON_REMOVE));
inOrder
.verify(mockListener)
.onPositionDiscontinuity(eq(oldPosition), eq(newPosition), eq(DISCONTINUITY_REASON_REMOVE));
inOrder.verify(mockListener, never()).onPositionDiscontinuity(anyInt());
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
}
@Test @Test
public void addMediaItems_callsRemoteMediaClient() { public void addMediaItems_callsRemoteMediaClient() {
MediaItem.Builder builder = new MediaItem.Builder(); MediaItem.Builder builder = new MediaItem.Builder();
...@@ -486,12 +592,14 @@ public class CastPlayerTest { ...@@ -486,12 +592,14 @@ public class CastPlayerTest {
castPlayer.addMediaItems(mediaItems); castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1); updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
verify(mockListener) InOrder inOrder = Mockito.inOrder(mockListener);
inOrder
.verify(mockListener)
.onMediaItemTransition( .onMediaItemTransition(
mediaItemCaptor.capture(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED)); mediaItemCaptor.capture(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
inOrder.verify(mockListener, never()).onMediaItemTransition(any(), anyInt());
assertThat(mediaItemCaptor.getValue().playbackProperties.tag) assertThat(mediaItemCaptor.getValue().playbackProperties.tag)
.isEqualTo(mediaItem.playbackProperties.tag); .isEqualTo(mediaItem.playbackProperties.tag);
verify(mockListener).onMediaItemTransition(any(), anyInt());
} }
@Test @Test
...@@ -501,17 +609,74 @@ public class CastPlayerTest { ...@@ -501,17 +609,74 @@ public class CastPlayerTest {
castPlayer.addMediaItems(mediaItems); castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1); updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
verify(mockListener).onMediaItemTransition(any(), anyInt());
castPlayer.clearMediaItems(); castPlayer.clearMediaItems();
updateTimeLine( updateTimeLine(
/* mediaItems= */ ImmutableList.of(), /* mediaItems= */ ImmutableList.of(),
/* mediaQueueItemIds= */ new int[0], /* mediaQueueItemIds= */ new int[0],
/* currentItemId= */ C.INDEX_UNSET); /* currentItemId= */ C.INDEX_UNSET);
verify(mockListener)
InOrder inOrder = Mockito.inOrder(mockListener);
inOrder
.verify(mockListener)
.onMediaItemTransition(any(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
inOrder
.verify(mockListener)
.onMediaItemTransition( .onMediaItemTransition(
/* mediaItem= */ null, Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED); /* mediaItem= */ null, Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED);
verify(mockListener, times(2)).onMediaItemTransition(any(), anyInt()); inOrder.verify(mockListener, never()).onMediaItemTransition(any(), anyInt());
}
@Test
@SuppressWarnings("deprecation") // Mocks deprecated method used by the CastPlayer.
public void clearMediaItems_notifiesPositionDiscontinuity() {
int[] mediaQueueItemIds = new int[] {1, 2};
List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds);
castPlayer.addMediaItems(mediaItems);
updateTimeLine(
mediaItems,
mediaQueueItemIds,
/* currentItemId= */ 1,
new int[] {MediaInfo.STREAM_TYPE_BUFFERED, MediaInfo.STREAM_TYPE_BUFFERED},
/* durationsMs= */ new long[] {20_000L, 30_000L},
/* positionMs= */ 1234);
castPlayer.clearMediaItems();
updateTimeLine(
/* mediaItems= */ ImmutableList.of(),
/* mediaQueueItemIds= */ new int[0],
/* currentItemId= */ C.INDEX_UNSET,
new int[] {MediaInfo.STREAM_TYPE_BUFFERED},
/* durationsMs= */ new long[] {20_000L},
/* positionMs= */ 0);
Player.PositionInfo oldPosition =
new Player.PositionInfo(
/* windowUid= */ 1,
/* windowIndex= */ 0,
/* periodUid= */ 1,
/* periodIndex= */ 0,
/* positionMs= */ 1234,
/* contentPositionMs= */ 1234,
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
Player.PositionInfo newPosition =
new Player.PositionInfo(
/* windowUid= */ null,
/* windowIndex= */ 0,
/* periodUid= */ null,
/* periodIndex= */ 0,
/* positionMs= */ 0,
/* contentPositionMs= */ 0,
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
InOrder inOrder = Mockito.inOrder(mockListener);
inOrder.verify(mockListener).onPositionDiscontinuity(eq(Player.DISCONTINUITY_REASON_REMOVE));
inOrder
.verify(mockListener)
.onPositionDiscontinuity(
eq(oldPosition), eq(newPosition), eq(Player.DISCONTINUITY_REASON_REMOVE));
inOrder.verify(mockListener, never()).onPositionDiscontinuity(anyInt());
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
} }
@Test @Test
...@@ -523,19 +688,160 @@ public class CastPlayerTest { ...@@ -523,19 +688,160 @@ public class CastPlayerTest {
castPlayer.addMediaItems(mediaItems); castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1); updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
verify(mockListener).onMediaItemTransition(any(), anyInt()); castPlayer.removeMediaItem(/* index= */ 0);
// Update with the new timeline after removal.
updateTimeLine(
ImmutableList.of(mediaItem2),
/* mediaQueueItemIds= */ new int[] {2},
/* currentItemId= */ 2);
InOrder inOrder = Mockito.inOrder(mockListener);
inOrder
.verify(mockListener, times(2))
.onMediaItemTransition(
mediaItemCaptor.capture(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
inOrder.verify(mockListener, never()).onMediaItemTransition(any(), anyInt());
assertThat(mediaItemCaptor.getAllValues().get(0).playbackProperties.tag)
.isEqualTo(mediaItem1.playbackProperties.tag);
assertThat(mediaItemCaptor.getAllValues().get(1).playbackProperties.tag)
.isEqualTo(mediaItem2.playbackProperties.tag);
}
@Test
@SuppressWarnings("deprecation") // Mocks deprecated method used by the CastPlayer.
public void removeCurrentMediaItem_notifiesPositionDiscontinuity() {
MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1);
MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2);
List<MediaItem> mediaItems = ImmutableList.of(mediaItem1, mediaItem2);
int[] mediaQueueItemIds = new int[] {1, 2};
castPlayer.addMediaItems(mediaItems);
updateTimeLine(
mediaItems,
mediaQueueItemIds,
/* currentItemId= */ 1,
new int[] {MediaInfo.STREAM_TYPE_BUFFERED, MediaInfo.STREAM_TYPE_BUFFERED},
/* durationsMs= */ new long[] {20_000L, 30_000L},
/* positionMs= */ 1234);
castPlayer.removeMediaItem(/* index= */ 0); castPlayer.removeMediaItem(/* index= */ 0);
// Update with the new timeline after removal.
updateTimeLine(
ImmutableList.of(mediaItem2),
/* mediaQueueItemIds= */ new int[] {2},
/* currentItemId= */ 2,
new int[] {MediaInfo.STREAM_TYPE_BUFFERED},
/* durationsMs= */ new long[] {20_000L},
/* positionMs= */ 0);
Player.PositionInfo oldPosition =
new Player.PositionInfo(
/* windowUid= */ 1,
/* windowIndex= */ 0,
/* periodUid= */ 1,
/* periodIndex= */ 0,
/* positionMs= */ 1234,
/* contentPositionMs= */ 1234,
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
Player.PositionInfo newPosition =
new Player.PositionInfo(
/* windowUid= */ 2,
/* windowIndex= */ 0,
/* periodUid= */ 2,
/* periodIndex= */ 0,
/* positionMs= */ 0,
/* contentPositionMs= */ 0,
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
InOrder inOrder = Mockito.inOrder(mockListener);
inOrder.verify(mockListener).onPositionDiscontinuity(eq(Player.DISCONTINUITY_REASON_REMOVE));
inOrder
.verify(mockListener)
.onPositionDiscontinuity(
eq(oldPosition), eq(newPosition), eq(Player.DISCONTINUITY_REASON_REMOVE));
inOrder.verify(mockListener, never()).onPositionDiscontinuity(anyInt());
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
}
@Test
public void removeCurrentMediaItem_byRemoteClient_notifiesMediaItemTransition() {
MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1);
MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2);
List<MediaItem> mediaItems = ImmutableList.of(mediaItem1, mediaItem2);
castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, new int[] {1, 2}, /* currentItemId= */ 1);
// Update with the new timeline after removal on the device.
updateTimeLine( updateTimeLine(
ImmutableList.of(mediaItem2), ImmutableList.of(mediaItem2),
/* mediaQueueItemIds= */ new int[] {2}, /* mediaQueueItemIds= */ new int[] {2},
/* currentItemId= */ 2); /* currentItemId= */ 2);
verify(mockListener, times(2))
InOrder inOrder = Mockito.inOrder(mockListener);
inOrder
.verify(mockListener, times(2))
.onMediaItemTransition( .onMediaItemTransition(
mediaItemCaptor.capture(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED)); mediaItemCaptor.capture(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
assertThat(mediaItemCaptor.getValue().playbackProperties.tag) inOrder.verify(mockListener, never()).onMediaItemTransition(any(), anyInt());
List<MediaItem> capturedMediaItems = mediaItemCaptor.getAllValues();
assertThat(capturedMediaItems.get(0).playbackProperties.tag)
.isEqualTo(mediaItem1.playbackProperties.tag);
assertThat(capturedMediaItems.get(1).playbackProperties.tag)
.isEqualTo(mediaItem2.playbackProperties.tag); .isEqualTo(mediaItem2.playbackProperties.tag);
verify(mockListener, times(2)).onMediaItemTransition(any(), anyInt()); }
@Test
@SuppressWarnings("deprecation") // Mocks deprecated method used by the CastPlayer.
public void removeCurrentMediaItem_byRemoteClient_notifiesPositionDiscontinuity() {
MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1);
MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2);
List<MediaItem> mediaItems = ImmutableList.of(mediaItem1, mediaItem2);
castPlayer.addMediaItems(mediaItems);
updateTimeLine(
mediaItems,
new int[] {1, 2},
/* currentItemId= */ 1,
new int[] {MediaInfo.STREAM_TYPE_BUFFERED, MediaInfo.STREAM_TYPE_BUFFERED},
/* durationsMs= */ new long[] {20_000L, 30_000L},
/* positionMs= */ 1234);
// Update with the new timeline after removal on the device.
updateTimeLine(
ImmutableList.of(mediaItem2),
/* mediaQueueItemIds= */ new int[] {2},
/* currentItemId= */ 2,
new int[] {MediaInfo.STREAM_TYPE_BUFFERED},
/* durationsMs= */ new long[] {30_000L},
/* positionMs= */ 0);
Player.PositionInfo oldPosition =
new Player.PositionInfo(
/* windowUid= */ 1,
/* windowIndex= */ 0,
/* periodUid= */ 1,
/* periodIndex= */ 0,
/* positionMs= */ 0, // position at which we receive the timeline change
/* contentPositionMs= */ 0, // position at which we receive the timeline change
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
Player.PositionInfo newPosition =
new Player.PositionInfo(
/* windowUid= */ 2,
/* windowIndex= */ 0,
/* periodUid= */ 2,
/* periodIndex= */ 0,
/* positionMs= */ 0,
/* contentPositionMs= */ 0,
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
InOrder inOrder = Mockito.inOrder(mockListener);
inOrder.verify(mockListener).onPositionDiscontinuity(eq(Player.DISCONTINUITY_REASON_REMOVE));
inOrder
.verify(mockListener)
.onPositionDiscontinuity(
eq(oldPosition), eq(newPosition), eq(Player.DISCONTINUITY_REASON_REMOVE));
inOrder.verify(mockListener, never()).onPositionDiscontinuity(anyInt());
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
} }
@Test @Test
...@@ -547,14 +853,37 @@ public class CastPlayerTest { ...@@ -547,14 +853,37 @@ public class CastPlayerTest {
castPlayer.addMediaItems(mediaItems); castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1); updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
verify(mockListener).onMediaItemTransition(any(), anyInt()); castPlayer.removeMediaItem(/* index= */ 1);
updateTimeLine(
ImmutableList.of(mediaItem1),
/* mediaQueueItemIds= */ new int[] {1},
/* currentItemId= */ 1);
InOrder inOrder = Mockito.inOrder(mockListener);
inOrder
.verify(mockListener)
.onMediaItemTransition(any(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
inOrder.verify(mockListener, never()).onMediaItemTransition(any(), anyInt());
}
@Test
@SuppressWarnings("deprecation") // Mocks deprecated method used by the CastPlayer.
public void removeNonCurrentMediaItem_doesNotNotifyPositionDiscontinuity() {
MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1);
MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2);
List<MediaItem> mediaItems = ImmutableList.of(mediaItem1, mediaItem2);
int[] mediaQueueItemIds = new int[] {1, 2};
castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
castPlayer.removeMediaItem(/* index= */ 1); castPlayer.removeMediaItem(/* index= */ 1);
updateTimeLine( updateTimeLine(
ImmutableList.of(mediaItem1), ImmutableList.of(mediaItem1),
/* mediaQueueItemIds= */ new int[] {1}, /* mediaQueueItemIds= */ new int[] {1},
/* currentItemId= */ 1); /* currentItemId= */ 1);
verify(mockListener).onMediaItemTransition(any(), anyInt());
verify(mockListener, never()).onPositionDiscontinuity(anyInt());
verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
} }
@Test @Test
...@@ -568,15 +897,63 @@ public class CastPlayerTest { ...@@ -568,15 +897,63 @@ public class CastPlayerTest {
castPlayer.addMediaItems(mediaItems); castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1); updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
verify(mockListener).onMediaItemTransition(any(), anyInt()); castPlayer.seekTo(/* windowIndex= */ 1, /* positionMs= */ 1234);
castPlayer.seekTo(/* windowIndex= */ 1, /* positionMs= */ 0); InOrder inOrder = Mockito.inOrder(mockListener);
verify(mockListener) inOrder
.verify(mockListener)
.onMediaItemTransition(any(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
inOrder
.verify(mockListener)
.onMediaItemTransition( .onMediaItemTransition(
mediaItemCaptor.capture(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_SEEK)); mediaItemCaptor.capture(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_SEEK));
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
assertThat(mediaItemCaptor.getValue().playbackProperties.tag) assertThat(mediaItemCaptor.getValue().playbackProperties.tag)
.isEqualTo(mediaItem2.playbackProperties.tag); .isEqualTo(mediaItem2.playbackProperties.tag);
verify(mockListener, times(2)).onMediaItemTransition(any(), anyInt()); }
@Test
@SuppressWarnings("deprecation") // Mocks deprecated method used by the CastPlayer.
public void seekTo_otherWindow_notifiesPositionDiscontinuity() {
when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null)))
.thenReturn(mockPendingResult);
MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1);
MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2);
List<MediaItem> mediaItems = ImmutableList.of(mediaItem1, mediaItem2);
int[] mediaQueueItemIds = new int[] {1, 2};
castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
castPlayer.seekTo(/* windowIndex= */ 1, /* positionMs= */ 1234);
Player.PositionInfo oldPosition =
new Player.PositionInfo(
/* windowUid= */ 1,
/* windowIndex= */ 0,
/* periodUid= */ 1,
/* periodIndex= */ 0,
/* positionMs= */ 0,
/* contentPositionMs= */ 0,
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
Player.PositionInfo newPosition =
new Player.PositionInfo(
/* windowUid= */ 2,
/* windowIndex= */ 1,
/* periodUid= */ 2,
/* periodIndex= */ 1,
/* positionMs= */ 1234,
/* contentPositionMs= */ 1234,
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
InOrder inOrder = Mockito.inOrder(mockListener);
inOrder.verify(mockListener).onPositionDiscontinuity(eq(Player.DISCONTINUITY_REASON_SEEK));
inOrder
.verify(mockListener)
.onPositionDiscontinuity(
eq(oldPosition), eq(newPosition), eq(Player.DISCONTINUITY_REASON_SEEK));
inOrder.verify(mockListener, never()).onPositionDiscontinuity(anyInt());
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
} }
@Test @Test
...@@ -588,15 +965,82 @@ public class CastPlayerTest { ...@@ -588,15 +965,82 @@ public class CastPlayerTest {
castPlayer.addMediaItems(mediaItems); castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1); updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
verify(mockListener).onMediaItemTransition(any(), anyInt()); castPlayer.seekTo(/* windowIndex= */ 0, /* positionMs= */ 1234);
castPlayer.seekTo(/* windowIndex= */ 0, /* positionMs= */ 0); InOrder inOrder = Mockito.inOrder(mockListener);
verify(mockListener).onMediaItemTransition(any(), anyInt()); inOrder
.verify(mockListener)
.onMediaItemTransition(any(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
inOrder.verify(mockListener, never()).onMediaItemTransition(any(), anyInt());
} }
@Test @Test
@SuppressWarnings("deprecation") // Mocks deprecated method used by the CastPlayer. @SuppressWarnings("deprecation") // Mocks deprecated method used by the CastPlayer.
public void autoTransition_notifiesMediaItemTransitionAndPositionDiscontinuity() { public void seekTo_sameWindow_notifiesPositionDiscontinuity() {
when(mockRemoteMediaClient.seek(anyLong())).thenReturn(mockPendingResult);
int[] mediaQueueItemIds = new int[] {1, 2};
List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds);
castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
castPlayer.seekTo(/* windowIndex= */ 0, /* positionMs= */ 1234);
Player.PositionInfo oldPosition =
new Player.PositionInfo(
/* windowUid= */ 1,
/* windowIndex= */ 0,
/* periodUid= */ 1,
/* periodIndex= */ 0,
/* positionMs= */ 0,
/* contentPositionMs= */ 0,
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
Player.PositionInfo newPosition =
new Player.PositionInfo(
/* windowUid= */ 1,
/* windowIndex= */ 0,
/* periodUid= */ 1,
/* periodIndex= */ 0,
/* positionMs= */ 1234,
/* contentPositionMs= */ 1234,
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
InOrder inOrder = Mockito.inOrder(mockListener);
inOrder.verify(mockListener).onPositionDiscontinuity(eq(Player.DISCONTINUITY_REASON_SEEK));
inOrder
.verify(mockListener)
.onPositionDiscontinuity(
eq(oldPosition), eq(newPosition), eq(Player.DISCONTINUITY_REASON_SEEK));
inOrder.verify(mockListener, never()).onPositionDiscontinuity(anyInt());
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
}
@Test
public void autoTransition_notifiesMediaItemTransition() {
int[] mediaQueueItemIds = new int[] {1, 2};
// When the remote Cast player transitions to an item that wasn't played before, the media state
// delivers the duration for that media item which updates the timeline accordingly.
List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds);
castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 2);
InOrder inOrder = Mockito.inOrder(mockListener);
inOrder
.verify(mockListener)
.onMediaItemTransition(any(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
inOrder
.verify(mockListener)
.onMediaItemTransition(
mediaItemCaptor.capture(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_AUTO));
inOrder.verify(mockListener, never()).onMediaItemTransition(any(), anyInt());
assertThat(mediaItemCaptor.getValue().playbackProperties.tag).isEqualTo(2);
}
@Test
@SuppressWarnings("deprecation") // Mocks deprecated method used by the CastPlayer.
public void autoTransition_notifiesPositionDiscontinuity() {
int[] mediaQueueItemIds = new int[] {1, 2}; int[] mediaQueueItemIds = new int[] {1, 2};
int[] streamTypes = {MediaInfo.STREAM_TYPE_BUFFERED, MediaInfo.STREAM_TYPE_BUFFERED}; int[] streamTypes = {MediaInfo.STREAM_TYPE_BUFFERED, MediaInfo.STREAM_TYPE_BUFFERED};
long[] durationsFirstMs = {12500, C.TIME_UNSET}; long[] durationsFirstMs = {12500, C.TIME_UNSET};
...@@ -611,25 +1055,44 @@ public class CastPlayerTest { ...@@ -611,25 +1055,44 @@ public class CastPlayerTest {
mediaQueueItemIds, mediaQueueItemIds,
/* currentItemId= */ 1, /* currentItemId= */ 1,
/* streamTypes= */ streamTypes, /* streamTypes= */ streamTypes,
/* durationsMs= */ durationsFirstMs); /* durationsMs= */ durationsFirstMs,
/* positionMs= */ C.TIME_UNSET);
updateTimeLine( updateTimeLine(
mediaItems, mediaItems,
mediaQueueItemIds, mediaQueueItemIds,
/* currentItemId= */ 2, /* currentItemId= */ 2,
/* streamTypes= */ streamTypes, /* streamTypes= */ streamTypes,
/* durationsMs= */ durationsSecondMs); /* durationsMs= */ durationsSecondMs,
/* positionMs= */ C.TIME_UNSET);
Player.PositionInfo oldPosition =
new Player.PositionInfo(
/* windowUid= */ 1,
/* windowIndex= */ 0,
/* periodUid= */ 1,
/* periodIndex= */ 0,
/* positionMs= */ 12500,
/* contentPositionMs= */ 12500,
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
Player.PositionInfo newPosition =
new Player.PositionInfo(
/* windowUid= */ 2,
/* windowIndex= */ 1,
/* periodUid= */ 2,
/* periodIndex= */ 1,
/* positionMs= */ 0,
/* contentPositionMs= */ 0,
/* adGroupIndex= */ C.INDEX_UNSET,
/* adIndexInAdGroup= */ C.INDEX_UNSET);
InOrder inOrder = Mockito.inOrder(mockListener); InOrder inOrder = Mockito.inOrder(mockListener);
inOrder inOrder
.verify(mockListener) .verify(mockListener)
.onMediaItemTransition(any(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
inOrder
.verify(mockListener)
.onPositionDiscontinuity(eq(Player.DISCONTINUITY_REASON_AUTO_TRANSITION)); .onPositionDiscontinuity(eq(Player.DISCONTINUITY_REASON_AUTO_TRANSITION));
inOrder inOrder
.verify(mockListener) .verify(mockListener)
.onMediaItemTransition(any(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_AUTO)); .onPositionDiscontinuity(
inOrder.verify(mockListener, never()).onMediaItemTransition(any(), anyInt()); eq(oldPosition), eq(newPosition), eq(Player.DISCONTINUITY_REASON_AUTO_TRANSITION));
inOrder.verify(mockListener, never()).onPositionDiscontinuity(anyInt()); inOrder.verify(mockListener, never()).onPositionDiscontinuity(anyInt());
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt()); inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
} }
...@@ -674,7 +1137,13 @@ public class CastPlayerTest { ...@@ -674,7 +1137,13 @@ public class CastPlayerTest {
long[] durationsMs = new long[] {C.TIME_UNSET}; long[] durationsMs = new long[] {C.TIME_UNSET};
castPlayer.addMediaItem(mediaItem); castPlayer.addMediaItem(mediaItem);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1, streamTypes, durationsMs); updateTimeLine(
mediaItems,
mediaQueueItemIds,
/* currentItemId= */ 1,
streamTypes,
durationsMs,
/* positionMs= */ C.TIME_UNSET);
assertThat(castPlayer.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM)).isFalse(); assertThat(castPlayer.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM)).isFalse();
} }
...@@ -1041,7 +1510,13 @@ public class CastPlayerTest { ...@@ -1041,7 +1510,13 @@ public class CastPlayerTest {
int[] streamTypes = new int[mediaItems.size()]; int[] streamTypes = new int[mediaItems.size()];
Arrays.fill(streamTypes, MediaInfo.STREAM_TYPE_BUFFERED); Arrays.fill(streamTypes, MediaInfo.STREAM_TYPE_BUFFERED);
long[] durationsMs = new long[mediaItems.size()]; long[] durationsMs = new long[mediaItems.size()];
updateTimeLine(mediaItems, mediaQueueItemIds, currentItemId, streamTypes, durationsMs); updateTimeLine(
mediaItems,
mediaQueueItemIds,
currentItemId,
streamTypes,
durationsMs,
/* positionMs= */ C.TIME_UNSET);
} }
private void updateTimeLine( private void updateTimeLine(
...@@ -1049,7 +1524,8 @@ public class CastPlayerTest { ...@@ -1049,7 +1524,8 @@ public class CastPlayerTest {
int[] mediaQueueItemIds, int[] mediaQueueItemIds,
int currentItemId, int currentItemId,
int[] streamTypes, int[] streamTypes,
long[] durationsMs) { long[] durationsMs,
long positionMs) {
// Set up mocks to allow the player to update the timeline. // Set up mocks to allow the player to update the timeline.
List<MediaQueueItem> queueItems = new ArrayList<>(); List<MediaQueueItem> queueItems = new ArrayList<>();
for (int i = 0; i < mediaQueueItemIds.length; i++) { for (int i = 0; i < mediaQueueItemIds.length; i++) {
...@@ -1074,6 +1550,9 @@ public class CastPlayerTest { ...@@ -1074,6 +1550,9 @@ public class CastPlayerTest {
when(mockMediaStatus.getMediaInfo()).thenReturn(mediaInfo); when(mockMediaStatus.getMediaInfo()).thenReturn(mediaInfo);
} }
} }
if (positionMs != C.TIME_UNSET) {
when(mockRemoteMediaClient.getApproximateStreamPosition()).thenReturn(positionMs);
}
when(mockMediaQueue.getItemIds()).thenReturn(mediaQueueItemIds); when(mockMediaQueue.getItemIds()).thenReturn(mediaQueueItemIds);
when(mockMediaStatus.getQueueItems()).thenReturn(queueItems); when(mockMediaStatus.getQueueItems()).thenReturn(queueItems);
when(mockMediaStatus.getCurrentItemId()) when(mockMediaStatus.getCurrentItemId())
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment