Enable onMediaMetadataChanged in CastPlayer

Issue: androidx/media#25
PiperOrigin-RevId: 460476841
This commit is contained in:
bachinger 2022-07-12 16:04:45 +00:00 committed by Rohit Singh
parent 223922fb11
commit 6922bd58ee
3 changed files with 134 additions and 4 deletions

View File

@ -40,6 +40,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)

View File

@ -147,6 +147,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.
@ -214,6 +215,7 @@ public final class CastPlayer extends BasePlayer {
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;
@ -427,6 +429,13 @@ public final class CastPlayer extends BasePlayer {
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) {
@ -564,8 +573,12 @@ public final class CastPlayer extends BasePlayer {
@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
@ -762,6 +775,7 @@ public final class CastPlayer extends BasePlayer {
return;
}
int oldWindowIndex = this.currentWindowIndex;
MediaMetadata oldMediaMetadata = mediaMetadata;
@Nullable
Object oldPeriodUid =
!getCurrentTimeline().isEmpty()
@ -773,6 +787,7 @@ public final class CastPlayer extends BasePlayer {
boolean playingPeriodChangedByTimelineChange = updateTimelineAndNotifyIfChanged();
Timeline currentTimeline = getCurrentTimeline();
currentWindowIndex = fetchCurrentWindowIndex(remoteMediaClient, currentTimeline);
mediaMetadata = getMediaMetadataInternal();
@Nullable
Object currentPeriodUid =
!currentTimeline.isEmpty()
@ -826,6 +841,11 @@ public final class CastPlayer extends BasePlayer {
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();
}

View File

@ -67,6 +67,7 @@ import androidx.media3.common.MediaMetadata;
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;
@ -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
@ -1042,7 +1043,9 @@ public class CastPlayerTest {
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
@ -1053,6 +1056,8 @@ public class CastPlayerTest {
.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
@ -1773,6 +1778,108 @@ public class CastPlayerTest {
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++) {
@ -1792,7 +1899,8 @@ public class CastPlayerTest {
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();