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`
|
`Window.mediaItem` in `CastTimeline`
|
||||||
([#25](https://github.com/androidx/media/issues/25),
|
([#25](https://github.com/androidx/media/issues/25),
|
||||||
[#8212](https://github.com/google/ExoPlayer/issues/8212)).
|
[#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)
|
### 1.0.0-beta01 (2022-06-16)
|
||||||
|
|
||||||
|
@ -147,6 +147,7 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
private int pendingSeekWindowIndex;
|
private int pendingSeekWindowIndex;
|
||||||
private long pendingSeekPositionMs;
|
private long pendingSeekPositionMs;
|
||||||
@Nullable private PositionInfo pendingMediaItemRemovalPosition;
|
@Nullable private PositionInfo pendingMediaItemRemovalPosition;
|
||||||
|
private MediaMetadata mediaMetadata;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new cast player.
|
* Creates a new cast player.
|
||||||
@ -214,6 +215,7 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
playbackParameters = new StateHolder<>(PlaybackParameters.DEFAULT);
|
playbackParameters = new StateHolder<>(PlaybackParameters.DEFAULT);
|
||||||
playbackState = STATE_IDLE;
|
playbackState = STATE_IDLE;
|
||||||
currentTimeline = CastTimeline.EMPTY_CAST_TIMELINE;
|
currentTimeline = CastTimeline.EMPTY_CAST_TIMELINE;
|
||||||
|
mediaMetadata = MediaMetadata.EMPTY;
|
||||||
currentTracks = Tracks.EMPTY;
|
currentTracks = Tracks.EMPTY;
|
||||||
availableCommands = new Commands.Builder().addAll(PERMANENT_AVAILABLE_COMMANDS).build();
|
availableCommands = new Commands.Builder().addAll(PERMANENT_AVAILABLE_COMMANDS).build();
|
||||||
pendingSeekWindowIndex = C.INDEX_UNSET;
|
pendingSeekWindowIndex = C.INDEX_UNSET;
|
||||||
@ -427,6 +429,13 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
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));
|
||||||
|
MediaMetadata oldMediaMetadata = mediaMetadata;
|
||||||
|
mediaMetadata = getMediaMetadataInternal();
|
||||||
|
if (!oldMediaMetadata.equals(mediaMetadata)) {
|
||||||
|
listeners.queueEvent(
|
||||||
|
Player.EVENT_MEDIA_METADATA_CHANGED,
|
||||||
|
listener -> listener.onMediaMetadataChanged(mediaMetadata));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
updateAvailableCommandsAndNotifyIfChanged();
|
updateAvailableCommandsAndNotifyIfChanged();
|
||||||
} else if (pendingSeekCount == 0) {
|
} else if (pendingSeekCount == 0) {
|
||||||
@ -564,8 +573,12 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MediaMetadata getMediaMetadata() {
|
public MediaMetadata getMediaMetadata() {
|
||||||
// CastPlayer does not currently support metadata.
|
return mediaMetadata;
|
||||||
return MediaMetadata.EMPTY;
|
}
|
||||||
|
|
||||||
|
public MediaMetadata getMediaMetadataInternal() {
|
||||||
|
MediaItem currentMediaItem = getCurrentMediaItem();
|
||||||
|
return currentMediaItem != null ? currentMediaItem.mediaMetadata : MediaMetadata.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -762,6 +775,7 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int oldWindowIndex = this.currentWindowIndex;
|
int oldWindowIndex = this.currentWindowIndex;
|
||||||
|
MediaMetadata oldMediaMetadata = mediaMetadata;
|
||||||
@Nullable
|
@Nullable
|
||||||
Object oldPeriodUid =
|
Object oldPeriodUid =
|
||||||
!getCurrentTimeline().isEmpty()
|
!getCurrentTimeline().isEmpty()
|
||||||
@ -773,6 +787,7 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
boolean playingPeriodChangedByTimelineChange = updateTimelineAndNotifyIfChanged();
|
boolean playingPeriodChangedByTimelineChange = updateTimelineAndNotifyIfChanged();
|
||||||
Timeline currentTimeline = getCurrentTimeline();
|
Timeline currentTimeline = getCurrentTimeline();
|
||||||
currentWindowIndex = fetchCurrentWindowIndex(remoteMediaClient, currentTimeline);
|
currentWindowIndex = fetchCurrentWindowIndex(remoteMediaClient, currentTimeline);
|
||||||
|
mediaMetadata = getMediaMetadataInternal();
|
||||||
@Nullable
|
@Nullable
|
||||||
Object currentPeriodUid =
|
Object currentPeriodUid =
|
||||||
!currentTimeline.isEmpty()
|
!currentTimeline.isEmpty()
|
||||||
@ -826,6 +841,11 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
listeners.queueEvent(
|
listeners.queueEvent(
|
||||||
Player.EVENT_TRACKS_CHANGED, listener -> listener.onTracksChanged(currentTracks));
|
Player.EVENT_TRACKS_CHANGED, listener -> listener.onTracksChanged(currentTracks));
|
||||||
}
|
}
|
||||||
|
if (!oldMediaMetadata.equals(mediaMetadata)) {
|
||||||
|
listeners.queueEvent(
|
||||||
|
Player.EVENT_MEDIA_METADATA_CHANGED,
|
||||||
|
listener -> listener.onMediaMetadataChanged(mediaMetadata));
|
||||||
|
}
|
||||||
updateAvailableCommandsAndNotifyIfChanged();
|
updateAvailableCommandsAndNotifyIfChanged();
|
||||||
listeners.flushEvents();
|
listeners.flushEvents();
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,7 @@ import androidx.media3.common.MediaMetadata;
|
|||||||
import androidx.media3.common.MimeTypes;
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.PlaybackParameters;
|
import androidx.media3.common.PlaybackParameters;
|
||||||
import androidx.media3.common.Player;
|
import androidx.media3.common.Player;
|
||||||
|
import androidx.media3.common.Player.Listener;
|
||||||
import androidx.media3.common.Timeline;
|
import androidx.media3.common.Timeline;
|
||||||
import androidx.media3.common.util.Assertions;
|
import androidx.media3.common.util.Assertions;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
@ -107,7 +108,7 @@ public class CastPlayerTest {
|
|||||||
@Mock private CastContext mockCastContext;
|
@Mock private CastContext mockCastContext;
|
||||||
@Mock private SessionManager mockSessionManager;
|
@Mock private SessionManager mockSessionManager;
|
||||||
@Mock private CastSession mockCastSession;
|
@Mock private CastSession mockCastSession;
|
||||||
@Mock private Player.Listener mockListener;
|
@Mock private Listener mockListener;
|
||||||
@Mock private PendingResult<RemoteMediaClient.MediaChannelResult> mockPendingResult;
|
@Mock private PendingResult<RemoteMediaClient.MediaChannelResult> mockPendingResult;
|
||||||
|
|
||||||
@Captor
|
@Captor
|
||||||
@ -1042,7 +1043,9 @@ public class CastPlayerTest {
|
|||||||
|
|
||||||
castPlayer.addMediaItems(mediaItems);
|
castPlayer.addMediaItems(mediaItems);
|
||||||
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
|
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
|
||||||
|
MediaMetadata firstMediaMetadata = castPlayer.getMediaMetadata();
|
||||||
castPlayer.seekTo(/* mediaItemIndex= */ 1, /* positionMs= */ 1234);
|
castPlayer.seekTo(/* mediaItemIndex= */ 1, /* positionMs= */ 1234);
|
||||||
|
MediaMetadata secondMediaMetadata = castPlayer.getMediaMetadata();
|
||||||
|
|
||||||
InOrder inOrder = Mockito.inOrder(mockListener);
|
InOrder inOrder = Mockito.inOrder(mockListener);
|
||||||
inOrder
|
inOrder
|
||||||
@ -1053,6 +1056,8 @@ public class CastPlayerTest {
|
|||||||
.verify(mockListener)
|
.verify(mockListener)
|
||||||
.onMediaItemTransition(eq(mediaItem2), eq(Player.MEDIA_ITEM_TRANSITION_REASON_SEEK));
|
.onMediaItemTransition(eq(mediaItem2), eq(Player.MEDIA_ITEM_TRANSITION_REASON_SEEK));
|
||||||
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
|
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
|
||||||
|
assertThat(firstMediaMetadata).isEqualTo(mediaItem1.mediaMetadata);
|
||||||
|
assertThat(secondMediaMetadata).isEqualTo(mediaItem2.mediaMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -1773,6 +1778,108 @@ public class CastPlayerTest {
|
|||||||
verify(mockListener).onAvailableCommandsChanged(any());
|
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) {
|
private int[] createMediaQueueItemIds(int numberOfIds) {
|
||||||
int[] mediaQueueItemIds = new int[numberOfIds];
|
int[] mediaQueueItemIds = new int[numberOfIds];
|
||||||
for (int i = 0; i < numberOfIds; i++) {
|
for (int i = 0; i < numberOfIds; i++) {
|
||||||
@ -1792,7 +1899,8 @@ public class CastPlayerTest {
|
|||||||
private MediaItem createMediaItem(int mediaQueueItemId) {
|
private MediaItem createMediaItem(int mediaQueueItemId) {
|
||||||
return new MediaItem.Builder()
|
return new MediaItem.Builder()
|
||||||
.setUri("http://www.google.com/video" + mediaQueueItemId)
|
.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)
|
.setMimeType(MimeTypes.APPLICATION_MPD)
|
||||||
.setTag(mediaQueueItemId)
|
.setTag(mediaQueueItemId)
|
||||||
.build();
|
.build();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user