mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Call new onPositionDiscontinuity callback in CastPlayer
PiperOrigin-RevId: 367020270
This commit is contained in:
parent
6f4db96da1
commit
4c33c5110e
2 changed files with 656 additions and 59 deletions
|
|
@ -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;
|
||||||
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 {
|
||||||
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 {
|
||||||
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);
|
||||||
|
} else {
|
||||||
|
remoteMediaClient.seek(positionMs).setResultCallback(seekResultCallback);
|
||||||
|
}
|
||||||
|
PositionInfo oldPosition = getCurrentPositionInfo();
|
||||||
|
pendingSeekCount++;
|
||||||
|
pendingSeekWindowIndex = windowIndex;
|
||||||
|
pendingSeekPositionMs = positionMs;
|
||||||
|
PositionInfo newPosition = getCurrentPositionInfo();
|
||||||
|
listeners.queueEvent(
|
||||||
|
Player.EVENT_POSITION_DISCONTINUITY,
|
||||||
|
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
|
// TODO(internal b/182261884): queue `onMediaItemTransition` event when the media item is
|
||||||
// repeated.
|
// repeated.
|
||||||
MediaItem mediaItem = currentTimeline.getWindow(windowIndex, window).mediaItem;
|
MediaItem mediaItem = getCurrentTimeline().getWindow(windowIndex, window).mediaItem;
|
||||||
listeners.queueEvent(
|
listeners.queueEvent(
|
||||||
Player.EVENT_MEDIA_ITEM_TRANSITION,
|
Player.EVENT_MEDIA_ITEM_TRANSITION,
|
||||||
listener ->
|
listener ->
|
||||||
listener.onMediaItemTransition(mediaItem, MEDIA_ITEM_TRANSITION_REASON_SEEK));
|
listener.onMediaItemTransition(mediaItem, MEDIA_ITEM_TRANSITION_REASON_SEEK));
|
||||||
} else {
|
|
||||||
remoteMediaClient.seek(positionMs).setResultCallback(seekResultCallback);
|
|
||||||
}
|
}
|
||||||
pendingSeekCount++;
|
|
||||||
pendingSeekWindowIndex = windowIndex;
|
|
||||||
pendingSeekPositionMs = positionMs;
|
|
||||||
// TODO(b/181262841): call new onPositionDiscontinuity callback
|
|
||||||
listeners.queueEvent(
|
|
||||||
Player.EVENT_POSITION_DISCONTINUITY,
|
|
||||||
listener -> listener.onPositionDiscontinuity(DISCONTINUITY_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 {
|
||||||
// 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 {
|
||||||
}
|
}
|
||||||
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 {
|
||||||
*/
|
*/
|
||||||
@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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
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;
|
||||||
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;
|
||||||
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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
|
|
||||||
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 {
|
||||||
|
|
||||||
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);
|
castPlayer.removeMediaItem(/* index= */ 0);
|
||||||
|
// Update with the new timeline after removal.
|
||||||
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());
|
||||||
|
assertThat(mediaItemCaptor.getAllValues().get(0).playbackProperties.tag)
|
||||||
|
.isEqualTo(mediaItem1.playbackProperties.tag);
|
||||||
|
assertThat(mediaItemCaptor.getAllValues().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_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);
|
||||||
|
// 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(
|
||||||
|
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());
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 {
|
||||||
|
|
||||||
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);
|
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());
|
|
||||||
|
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);
|
||||||
|
updateTimeLine(
|
||||||
|
ImmutableList.of(mediaItem1),
|
||||||
|
/* mediaQueueItemIds= */ new int[] {1},
|
||||||
|
/* currentItemId= */ 1);
|
||||||
|
|
||||||
|
verify(mockListener, never()).onPositionDiscontinuity(anyInt());
|
||||||
|
verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -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 {
|
||||||
|
|
||||||
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 {
|
||||||
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
|
|
||||||
.verify(mockListener)
|
|
||||||
.onMediaItemTransition(any(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
|
|
||||||
inOrder
|
inOrder
|
||||||
.verify(mockListener)
|
.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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
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())
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue