Skip to content

Commit

Permalink
Enable onMediaMetadataChanged in CastPlayer
Browse files Browse the repository at this point in the history
Issue: #25
PiperOrigin-RevId: 460476841
(cherry picked from commit 6922bd5)
  • Loading branch information
marcbaechinger authored and rohitjoins committed Jul 12, 2022
1 parent fff99fe commit 97716cd
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 4 deletions.
2 changes: 2 additions & 0 deletions RELEASENOTES.md
Expand Up @@ -34,6 +34,8 @@
`Window.mediaItem` in `CastTimeline`
([#25](https://github.com/androidx/media/issues/25),
[#8212](https://github.com/google/ExoPlayer/issues/8212)).
* Support `Player.getMetadata()` and `Listener.onMediaMetadataChanged()`
with `CastPlayer` ([#25](https://github.com/androidx/media/issues/25)).

### 1.0.0-beta01 (2022-06-16)

Expand Down
24 changes: 22 additions & 2 deletions libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java
Expand Up @@ -145,6 +145,7 @@ public final class CastPlayer extends BasePlayer {
private int pendingSeekWindowIndex;
private long pendingSeekPositionMs;
@Nullable private PositionInfo pendingMediaItemRemovalPosition;
private MediaMetadata mediaMetadata;

/**
* Creates a new cast player.
Expand Down Expand Up @@ -212,6 +213,7 @@ public CastPlayer(
playbackParameters = new StateHolder<>(PlaybackParameters.DEFAULT);
playbackState = STATE_IDLE;
currentTimeline = CastTimeline.EMPTY_CAST_TIMELINE;
mediaMetadata = MediaMetadata.EMPTY;
currentTracks = Tracks.EMPTY;
availableCommands = new Commands.Builder().addAll(PERMANENT_AVAILABLE_COMMANDS).build();
pendingSeekWindowIndex = C.INDEX_UNSET;
Expand Down Expand Up @@ -425,6 +427,13 @@ public void seekTo(int mediaItemIndex, long positionMs) {
Player.EVENT_MEDIA_ITEM_TRANSITION,
listener ->
listener.onMediaItemTransition(mediaItem, MEDIA_ITEM_TRANSITION_REASON_SEEK));
MediaMetadata oldMediaMetadata = mediaMetadata;
mediaMetadata = getMediaMetadataInternal();
if (!oldMediaMetadata.equals(mediaMetadata)) {
listeners.queueEvent(
Player.EVENT_MEDIA_METADATA_CHANGED,
listener -> listener.onMediaMetadataChanged(mediaMetadata));
}
}
updateAvailableCommandsAndNotifyIfChanged();
} else if (pendingSeekCount == 0) {
Expand Down Expand Up @@ -562,8 +571,12 @@ public void setTrackSelectionParameters(TrackSelectionParameters parameters) {}

@Override
public MediaMetadata getMediaMetadata() {
// CastPlayer does not currently support metadata.
return MediaMetadata.EMPTY;
return mediaMetadata;
}

public MediaMetadata getMediaMetadataInternal() {
MediaItem currentMediaItem = getCurrentMediaItem();
return currentMediaItem != null ? currentMediaItem.mediaMetadata : MediaMetadata.EMPTY;
}

@Override
Expand Down Expand Up @@ -760,6 +773,7 @@ private void updateInternalStateAndNotifyIfChanged() {
return;
}
int oldWindowIndex = this.currentWindowIndex;
MediaMetadata oldMediaMetadata = mediaMetadata;
@Nullable
Object oldPeriodUid =
!getCurrentTimeline().isEmpty()
Expand All @@ -771,6 +785,7 @@ private void updateInternalStateAndNotifyIfChanged() {
boolean playingPeriodChangedByTimelineChange = updateTimelineAndNotifyIfChanged();
Timeline currentTimeline = getCurrentTimeline();
currentWindowIndex = fetchCurrentWindowIndex(remoteMediaClient, currentTimeline);
mediaMetadata = getMediaMetadataInternal();
@Nullable
Object currentPeriodUid =
!currentTimeline.isEmpty()
Expand Down Expand Up @@ -824,6 +839,11 @@ private void updateInternalStateAndNotifyIfChanged() {
listeners.queueEvent(
Player.EVENT_TRACKS_CHANGED, listener -> listener.onTracksChanged(currentTracks));
}
if (!oldMediaMetadata.equals(mediaMetadata)) {
listeners.queueEvent(
Player.EVENT_MEDIA_METADATA_CHANGED,
listener -> listener.onMediaMetadataChanged(mediaMetadata));
}
updateAvailableCommandsAndNotifyIfChanged();
listeners.flushEvents();
}
Expand Down
112 changes: 110 additions & 2 deletions libraries/cast/src/test/java/androidx/media3/cast/CastPlayerTest.java
Expand Up @@ -67,6 +67,7 @@
import androidx.media3.common.MimeTypes;
import androidx.media3.common.PlaybackParameters;
import androidx.media3.common.Player;
import androidx.media3.common.Player.Listener;
import androidx.media3.common.Timeline;
import androidx.media3.common.util.Assertions;
import androidx.test.ext.junit.runners.AndroidJUnit4;
Expand Down Expand Up @@ -107,7 +108,7 @@ public class CastPlayerTest {
@Mock private CastContext mockCastContext;
@Mock private SessionManager mockSessionManager;
@Mock private CastSession mockCastSession;
@Mock private Player.Listener mockListener;
@Mock private Listener mockListener;
@Mock private PendingResult<RemoteMediaClient.MediaChannelResult> mockPendingResult;

@Captor
Expand Down Expand Up @@ -1042,7 +1043,9 @@ public void seekTo_otherWindow_notifiesMediaItemTransition() {

castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
MediaMetadata firstMediaMetadata = castPlayer.getMediaMetadata();
castPlayer.seekTo(/* mediaItemIndex= */ 1, /* positionMs= */ 1234);
MediaMetadata secondMediaMetadata = castPlayer.getMediaMetadata();

InOrder inOrder = Mockito.inOrder(mockListener);
inOrder
Expand All @@ -1053,6 +1056,8 @@ public void seekTo_otherWindow_notifiesMediaItemTransition() {
.verify(mockListener)
.onMediaItemTransition(eq(mediaItem2), eq(Player.MEDIA_ITEM_TRANSITION_REASON_SEEK));
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
assertThat(firstMediaMetadata).isEqualTo(mediaItem1.mediaMetadata);
assertThat(secondMediaMetadata).isEqualTo(mediaItem2.mediaMetadata);
}

@Test
Expand Down Expand Up @@ -1773,6 +1778,108 @@ public void setRepeatMode_one_doesNotNotifyAvailableCommandsChanged() {
verify(mockListener).onAvailableCommandsChanged(any());
}

@Test
public void setMediaItems_doesNotifyOnMetadataChanged() {
when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null)))
.thenReturn(mockPendingResult);
ArgumentCaptor<MediaMetadata> metadataCaptor = ArgumentCaptor.forClass(MediaMetadata.class);
String uri1 = "http://www.google.com/video1";
String uri2 = "http://www.google.com/video2";
ImmutableList<MediaItem> firstPlaylist =
ImmutableList.of(
new MediaItem.Builder()
.setUri(uri1)
.setMimeType(MimeTypes.APPLICATION_MPD)
.setMediaMetadata(new MediaMetadata.Builder().setArtist("foo").build())
.setTag(1)
.build());
ImmutableList<MediaItem> secondPlaylist =
ImmutableList.of(
new MediaItem.Builder()
.setUri(Uri.EMPTY)
.setTag(2)
.setMediaMetadata(new MediaMetadata.Builder().setArtist("bar").build())
.setMimeType(MimeTypes.APPLICATION_MPD)
.build(),
new MediaItem.Builder()
.setUri(uri2)
.setMimeType(MimeTypes.APPLICATION_MP4)
.setMediaMetadata(new MediaMetadata.Builder().setArtist("foobar").build())
.setTag(3)
.build());
castPlayer.addListener(mockListener);

MediaMetadata intitalMetadata = castPlayer.getMediaMetadata();
castPlayer.setMediaItems(firstPlaylist, /* startIndex= */ 0, /* startPositionMs= */ 2000L);
updateTimeLine(firstPlaylist, /* mediaQueueItemIds= */ new int[] {1}, /* currentItemId= */ 1);
MediaMetadata firstMetadata = castPlayer.getMediaMetadata();
// Replacing existing playlist.
castPlayer.setMediaItems(secondPlaylist, /* startIndex= */ 1, /* startPositionMs= */ 0L);
updateTimeLine(
secondPlaylist, /* mediaQueueItemIds= */ new int[] {2, 3}, /* currentItemId= */ 3);
MediaMetadata secondMetadata = castPlayer.getMediaMetadata();
castPlayer.seekTo(/* mediaItemIndex= */ 0, /* positionMs= */ 0);
MediaMetadata thirdMetadata = castPlayer.getMediaMetadata();

verify(mockListener, times(3)).onMediaItemTransition(mediaItemCaptor.capture(), anyInt());
assertThat(mediaItemCaptor.getAllValues())
.containsExactly(firstPlaylist.get(0), secondPlaylist.get(1), secondPlaylist.get(0))
.inOrder();
verify(mockListener, times(3)).onMediaMetadataChanged(metadataCaptor.capture());
assertThat(metadataCaptor.getAllValues())
.containsExactly(
firstPlaylist.get(0).mediaMetadata,
secondPlaylist.get(1).mediaMetadata,
secondPlaylist.get(0).mediaMetadata)
.inOrder();
assertThat(intitalMetadata).isEqualTo(MediaMetadata.EMPTY);
assertThat(ImmutableList.of(firstMetadata, secondMetadata, thirdMetadata))
.containsExactly(
firstPlaylist.get(0).mediaMetadata,
secondPlaylist.get(1).mediaMetadata,
secondPlaylist.get(0).mediaMetadata)
.inOrder();
}

@Test
public void setMediaItems_equalMetadata_doesNotNotifyOnMediaMetadataChanged() {
when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null)))
.thenReturn(mockPendingResult);
String uri1 = "http://www.google.com/video1";
String uri2 = "http://www.google.com/video2";
ImmutableList<MediaItem> firstPlaylist =
ImmutableList.of(
new MediaItem.Builder()
.setUri(uri1)
.setMimeType(MimeTypes.APPLICATION_MPD)
.setTag(1)
.build());
ImmutableList<MediaItem> secondPlaylist =
ImmutableList.of(
new MediaItem.Builder()
.setMediaMetadata(MediaMetadata.EMPTY)
.setUri(Uri.EMPTY)
.setTag(2)
.setMimeType(MimeTypes.APPLICATION_MPD)
.build(),
new MediaItem.Builder()
.setUri(uri2)
.setMimeType(MimeTypes.APPLICATION_MP4)
.setTag(3)
.build());
castPlayer.addListener(mockListener);

castPlayer.setMediaItems(firstPlaylist, /* startIndex= */ 0, /* startPositionMs= */ 2000L);
updateTimeLine(firstPlaylist, /* mediaQueueItemIds= */ new int[] {1}, /* currentItemId= */ 1);
castPlayer.setMediaItems(secondPlaylist, /* startIndex= */ 1, /* startPositionMs= */ 0L);
updateTimeLine(
secondPlaylist, /* mediaQueueItemIds= */ new int[] {2, 3}, /* currentItemId= */ 3);
castPlayer.seekTo(/* mediaItemIndex= */ 0, /* positionMs= */ 0);

verify(mockListener, times(3)).onMediaItemTransition(any(), anyInt());
verify(mockListener, never()).onMediaMetadataChanged(any());
}

private int[] createMediaQueueItemIds(int numberOfIds) {
int[] mediaQueueItemIds = new int[numberOfIds];
for (int i = 0; i < numberOfIds; i++) {
Expand All @@ -1792,7 +1899,8 @@ private List<MediaItem> createMediaItems(int[] mediaQueueItemIds) {
private MediaItem createMediaItem(int mediaQueueItemId) {
return new MediaItem.Builder()
.setUri("http://www.google.com/video" + mediaQueueItemId)
.setMediaMetadata(new MediaMetadata.Builder().setArtist("Foo Bar").build())
.setMediaMetadata(
new MediaMetadata.Builder().setArtist("Foo Bar - " + mediaQueueItemId).build())
.setMimeType(MimeTypes.APPLICATION_MPD)
.setTag(mediaQueueItemId)
.build();
Expand Down

0 comments on commit 97716cd

Please sign in to comment.