Merge pull request #2235 from MGaetan89:add_CastPlayer_playlistMetadata

PiperOrigin-RevId: 738455260
(cherry picked from commit 2d1bcc77be3acd0a8297220f7564483c12db32b3)
This commit is contained in:
Copybara-Service 2025-03-19 10:38:33 -07:00 committed by tonihei
parent dcb67102b9
commit 963bae9dd8
3 changed files with 123 additions and 8 deletions

View File

@ -1,5 +1,83 @@
# Release notes
* Cast extension:
* Add support for playlist metadata
([#2235](https://github.com/androidx/media/pull/2235)).
### Unreleased changes
* Common Library:
* ExoPlayer:
* Transformer:
* Track Selection:
* Extractors:
* MP3: Use duration and data size from unseekable Xing, VBRI and similar
variable bitrate metadata when falling back to constant bitrate seeking
due to `FLAG_ENABLE_CONSTANT_BITRATE_SEEKING(_ALWAYS)`
([#2194](https://github.com/androidx/media/issues/2194)).
* DataSource:
* Audio:
* Allow constant power upmixing/downmixing in DefaultAudioMixer.
* Video:
* Add experimental `ExoPlayer` API to include the
`MediaCodec.BUFFER_FLAG_DECODE_ONLY` flag when queuing decode-only input
buffers. This flag will signal the decoder to skip the decode-only
buffers thereby resulting in faster seeking. Enable it with
`DefaultRenderersFactory.experimentalSetEnableMediaCodecBufferDecodeOnlyFlag`.
* Text:
* Metadata:
* Image:
* DataSource:
* DRM:
* Effect:
* Add `Presentation.createForShortSide(int)` that creates a `Presentation`
that ensures the shortest side always matches the given value,
regardless of input orientation.
* Muxers:
* `writeSampleData()` API now uses muxer specific `BufferInfo` class
instead of `MediaCodec.BufferInfo`.
* IMA extension:
* Session:
* UI:
* Downloads:
* Add partial download support for progressive streams. Apps can prepare a
progressive stream with `DownloadHelper`, and request a
`DownloadRequest` from the helper with specifying the time-based media
start and end positions that the download should cover. The returned
`DownloadRequest` carries the resolved byte range, with which a
`ProgressiveDownloader` can be created and download the content
correspondingly.
* OkHttp extension:
* Cronet extension:
* RTMP extension:
* HLS extension:
* DASH extension:
* Smooth Streaming extension:
* RTSP extension:
* Decoder extensions (FFmpeg, VP9, AV1, etc.):
* MIDI extension:
* Leanback extension:
* Cast extension:
* Test Utilities:
* Demo app:
* Add `PlaybackSpeedPopUpButton` Composable UI element to be part of
`ExtraControls` in `demo-compose`.
* Remove deprecated symbols:
* Removed deprecated `SegmentDownloader` constructor
`SegmentDownloader(MediaItem, Parser<M>, CacheDataSource.Factory,
Executor)` and the corresponding constructors in its subclasses
`DashDownloader`, `HlsDownloader` and `SsDownloader`.
* Removed deprecated `Player.hasNext()`, `Player.hasNextWindow()`. Use
`Player.hasNextMediaItem()` instead.
* Removed deprecated `Player.next()`. Use `Player.seekToNextMediaItem()`
instead.
* Removed deprecated `Player.seekToPreviousWindow()`. Use
`Player.seekToPreviousMediaItem()` instead.
* Removed deprecated `Player.seekToNextWindow()`. Use
`Player.seekToNextMediaItem()` instead.
* Removed deprecated `BaseAudioProcessor` in `exoplayer` module. Use
`BaseAudioProcessor` under `common` module.
## 1.6
### 1.6.0 (2025-03-26)

View File

@ -16,6 +16,7 @@
package androidx.media3.cast;
import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Util.SDK_INT;
import static androidx.media3.common.util.Util.castNonNull;
import static java.lang.Math.min;
@ -166,6 +167,7 @@ public final class CastPlayer extends BasePlayer {
private long pendingSeekPositionMs;
@Nullable private PositionInfo pendingMediaItemRemovalPosition;
private MediaMetadata mediaMetadata;
private MediaMetadata playlistMetadata;
private DeviceInfo deviceInfo;
/**
@ -268,6 +270,7 @@ public final class CastPlayer extends BasePlayer {
playbackState = STATE_IDLE;
currentTimeline = CastTimeline.EMPTY_CAST_TIMELINE;
mediaMetadata = MediaMetadata.EMPTY;
playlistMetadata = MediaMetadata.EMPTY;
currentTracks = Tracks.EMPTY;
availableCommands = new Commands.Builder().addAll(PERMANENT_AVAILABLE_COMMANDS).build();
pendingSeekWindowIndex = C.INDEX_UNSET;
@ -656,14 +659,19 @@ public final class CastPlayer extends BasePlayer {
@Override
public MediaMetadata getPlaylistMetadata() {
// CastPlayer does not currently support metadata.
return MediaMetadata.EMPTY;
return playlistMetadata;
}
/** This method is not supported and does nothing. */
@Override
public void setPlaylistMetadata(MediaMetadata mediaMetadata) {
// CastPlayer does not currently support metadata.
public void setPlaylistMetadata(MediaMetadata playlistMetadata) {
checkNotNull(playlistMetadata);
if (playlistMetadata.equals(this.playlistMetadata)) {
return;
}
this.playlistMetadata = playlistMetadata;
listeners.sendEvent(
EVENT_PLAYLIST_METADATA_CHANGED,
listener -> listener.onPlaylistMetadataChanged(this.playlistMetadata));
}
@Override

View File

@ -1800,7 +1800,7 @@ public class CastPlayerTest {
}
@Test
public void setMediaItems_doesNotifyOnMetadataChanged() {
public void setMediaItems_doesNotifyOnMediaMetadataChanged() {
when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null)))
.thenReturn(mockPendingResult);
ArgumentCaptor<MediaMetadata> metadataCaptor = ArgumentCaptor.forClass(MediaMetadata.class);
@ -1827,7 +1827,7 @@ public class CastPlayerTest {
.build());
castPlayer.addListener(mockListener);
MediaMetadata intitalMetadata = castPlayer.getMediaMetadata();
MediaMetadata initialMetadata = castPlayer.getMediaMetadata();
castPlayer.setMediaItems(firstPlaylist, /* startIndex= */ 0, /* startPositionMs= */ 2000L);
updateTimeLine(firstPlaylist, /* mediaQueueItemIds= */ new int[] {1}, /* currentItemId= */ 1);
MediaMetadata firstMetadata = castPlayer.getMediaMetadata();
@ -1850,7 +1850,7 @@ public class CastPlayerTest {
secondPlaylist.get(1).mediaMetadata,
secondPlaylist.get(0).mediaMetadata)
.inOrder();
assertThat(intitalMetadata).isEqualTo(MediaMetadata.EMPTY);
assertThat(initialMetadata).isEqualTo(MediaMetadata.EMPTY);
assertThat(ImmutableList.of(firstMetadata, secondMetadata, thirdMetadata))
.containsExactly(
firstPlaylist.get(0).mediaMetadata,
@ -1898,6 +1898,35 @@ public class CastPlayerTest {
verify(mockListener, never()).onMediaMetadataChanged(any());
}
@Test
public void setPlaylistMetadata_doesNotifyOnPlaylistMetadataChanged() {
castPlayer.addListener(mockListener);
MediaMetadata metadata = new MediaMetadata.Builder().setArtist("foo").build();
assertThat(castPlayer.getPlaylistMetadata()).isEqualTo(MediaMetadata.EMPTY);
castPlayer.setPlaylistMetadata(metadata);
assertThat(castPlayer.getPlaylistMetadata()).isEqualTo(metadata);
verify(mockListener).onPlaylistMetadataChanged(metadata);
}
@Test
public void setPlaylistMetadata_equalMetadata_doesNotNotifyOnPlaylistMetadataChanged() {
castPlayer.addListener(mockListener);
MediaMetadata metadata = new MediaMetadata.Builder().setArtist("foo").build();
castPlayer.setPlaylistMetadata(metadata);
castPlayer.setPlaylistMetadata(metadata);
assertThat(castPlayer.getPlaylistMetadata()).isEqualTo(metadata);
verify(mockListener, times(1)).onPlaylistMetadataChanged(metadata);
}
@Test
public void getDeviceInfo_returnsCorrectDeviceInfoWithPlaybackTypeRemote() {
DeviceInfo deviceInfo = castPlayer.getDeviceInfo();