Enable onMediaMetadataChanged in CastPlayer
Issue: androidx/media#25 PiperOrigin-RevId: 460476841
This commit is contained in:
parent
223922fb11
commit
6922bd58ee
@ -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)
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user