Skip to content

Commit

Permalink
[Cast] Notify media item transition only when playing period removed
Browse files Browse the repository at this point in the history
When playback transitions automatically, the timeline may have changed because the cast device learned about the duration of the next media item and includes this in the new media status that is sent to the CastPlayer. In such a case we need to make sure that we don't report a media item transition with reason PLAYLIST_CHANGED but for reason AUTO.

PiperOrigin-RevId: 366025323
  • Loading branch information
marcbaechinger authored and ojw28 committed Apr 1, 2021
1 parent ffb5b41 commit 2fa3675
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,7 @@ private void updateInternalStateAndNotifyIfChanged() {
// There is no session. We leave the state of the player as it is now.
return;
}
int previousWindowIndex = this.currentWindowIndex;
boolean wasPlaying = playbackState == Player.STATE_READY && playWhenReady.value;
updatePlayerStateAndNotifyIfChanged(/* resultCallback= */ null);
boolean isPlaying = playbackState == Player.STATE_READY && playWhenReady.value;
Expand All @@ -658,10 +659,12 @@ private void updateInternalStateAndNotifyIfChanged() {
Player.EVENT_IS_PLAYING_CHANGED, listener -> listener.onIsPlayingChanged(isPlaying));
}
updateRepeatModeAndNotifyIfChanged(/* resultCallback= */ null);
updateTimelineAndNotifyIfChanged();
boolean playingPeriodChangedByTimelineChange = updateTimelineAndNotifyIfChanged();

int currentWindowIndex = fetchCurrentWindowIndex(remoteMediaClient, currentTimeline);
if (this.currentWindowIndex != currentWindowIndex && pendingSeekCount == 0) {
if (!playingPeriodChangedByTimelineChange
&& previousWindowIndex != currentWindowIndex
&& pendingSeekCount == 0) {
this.currentWindowIndex = currentWindowIndex;
// TODO(b/181262841): call new onPositionDiscontinuity callback
listeners.queueEvent(
Expand Down Expand Up @@ -714,10 +717,16 @@ private void updateRepeatModeAndNotifyIfChanged(@Nullable ResultCallback<?> resu
}
}

/**
* Updates the timeline and notifies {@link Player.EventListener event listeners} if required.
*
* @return Whether the timeline change has caused a change of the period currently being played.
*/
@SuppressWarnings("deprecation") // Calling deprecated listener method.
private void updateTimelineAndNotifyIfChanged() {
private boolean updateTimelineAndNotifyIfChanged() {
Timeline previousTimeline = currentTimeline;
int previousWindowIndex = currentWindowIndex;
boolean playingPeriodChanged = false;
if (updateTimeline()) {
// TODO: Differentiate TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED and
// TIMELINE_CHANGE_REASON_SOURCE_UPDATE [see internal: b/65152553].
Expand All @@ -732,24 +741,22 @@ private void updateTimelineAndNotifyIfChanged() {

updateAvailableCommandsAndNotifyIfChanged();

boolean mediaItemTransitioned;
if (currentTimeline.isEmpty() && previousTimeline.isEmpty()) {
mediaItemTransitioned = false;
} else if (currentTimeline.isEmpty() != previousTimeline.isEmpty()) {
mediaItemTransitioned = true;
} else {
if (currentTimeline.isEmpty() != previousTimeline.isEmpty()) {
// Timeline initially populated or timeline cleared.
playingPeriodChanged = true;
} else if (!currentTimeline.isEmpty()) {
Object previousWindowUid = previousTimeline.getWindow(previousWindowIndex, window).uid;
Object currentWindowUid = currentTimeline.getWindow(currentWindowIndex, window).uid;
mediaItemTransitioned = !currentWindowUid.equals(previousWindowUid);
playingPeriodChanged = currentTimeline.getIndexOfPeriod(previousWindowUid) == C.INDEX_UNSET;
}
if (mediaItemTransitioned) {
if (playingPeriodChanged) {
listeners.queueEvent(
Player.EVENT_MEDIA_ITEM_TRANSITION,
listener ->
listener.onMediaItemTransition(
getCurrentMediaItem(), MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
}
}
return playingPeriodChanged;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;

/** Tests for {@link CastPlayer}. */
@RunWith(AndroidJUnit4.class)
Expand Down Expand Up @@ -592,6 +594,46 @@ public void seekTo_sameWindow_doesNotNotifyMediaItemTransition() {
verify(mockListener).onMediaItemTransition(any(), anyInt());
}

@Test
@SuppressWarnings("deprecation") // Mocks deprecated method used by the CastPlayer.
public void autoTransition_notifiesMediaItemTransitionAndPositionDiscontinuity() {
int[] mediaQueueItemIds = new int[] {1, 2};
int[] streamTypes = {MediaInfo.STREAM_TYPE_BUFFERED, MediaInfo.STREAM_TYPE_BUFFERED};
long[] durationsFirstMs = {12500, C.TIME_UNSET};
// 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.
long[] durationsSecondMs = {12500, 22000};
List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds);

castPlayer.addMediaItems(mediaItems);
updateTimeLine(
mediaItems,
mediaQueueItemIds,
/* currentItemId= */ 1,
/* streamTypes= */ streamTypes,
/* durationsMs= */ durationsFirstMs);
updateTimeLine(
mediaItems,
mediaQueueItemIds,
/* currentItemId= */ 2,
/* streamTypes= */ streamTypes,
/* durationsMs= */ durationsSecondMs);

InOrder inOrder = Mockito.inOrder(mockListener);
inOrder
.verify(mockListener)
.onMediaItemTransition(any(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
inOrder
.verify(mockListener)
.onPositionDiscontinuity(eq(Player.DISCONTINUITY_REASON_AUTO_TRANSITION));
inOrder
.verify(mockListener)
.onMediaItemTransition(any(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_AUTO));
inOrder.verify(mockListener, never()).onMediaItemTransition(any(), anyInt());
inOrder.verify(mockListener, never()).onPositionDiscontinuity(anyInt());
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
}

@Test
public void isCommandAvailable_isTrueForAvailableCommands() {
int[] mediaQueueItemIds = new int[] {1, 2};
Expand Down Expand Up @@ -1038,7 +1080,7 @@ private void updateTimeLine(
.thenReturn(currentItemId == C.INDEX_UNSET ? 0 : currentItemId);

// Call listener to update the timeline of the player.
remoteMediaClientCallback.onQueueStatusUpdated();
remoteMediaClientCallback.onStatusUpdated();
}

private static Player.Commands createWithPermanentCommands(
Expand Down

0 comments on commit 2fa3675

Please sign in to comment.