mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Merge pull request #2235 from MGaetan89:add_CastPlayer_playlistMetadata
PiperOrigin-RevId: 738455260 (cherry picked from commit 2d1bcc77be3acd0a8297220f7564483c12db32b3)
This commit is contained in:
parent
dcb67102b9
commit
963bae9dd8
@ -1,5 +1,83 @@
|
|||||||
# Release notes
|
# 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
|
||||||
|
|
||||||
### 1.6.0 (2025-03-26)
|
### 1.6.0 (2025-03-26)
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package androidx.media3.cast;
|
package androidx.media3.cast;
|
||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkArgument;
|
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.SDK_INT;
|
||||||
import static androidx.media3.common.util.Util.castNonNull;
|
import static androidx.media3.common.util.Util.castNonNull;
|
||||||
import static java.lang.Math.min;
|
import static java.lang.Math.min;
|
||||||
@ -166,6 +167,7 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
private long pendingSeekPositionMs;
|
private long pendingSeekPositionMs;
|
||||||
@Nullable private PositionInfo pendingMediaItemRemovalPosition;
|
@Nullable private PositionInfo pendingMediaItemRemovalPosition;
|
||||||
private MediaMetadata mediaMetadata;
|
private MediaMetadata mediaMetadata;
|
||||||
|
private MediaMetadata playlistMetadata;
|
||||||
private DeviceInfo deviceInfo;
|
private DeviceInfo deviceInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -268,6 +270,7 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
playbackState = STATE_IDLE;
|
playbackState = STATE_IDLE;
|
||||||
currentTimeline = CastTimeline.EMPTY_CAST_TIMELINE;
|
currentTimeline = CastTimeline.EMPTY_CAST_TIMELINE;
|
||||||
mediaMetadata = MediaMetadata.EMPTY;
|
mediaMetadata = MediaMetadata.EMPTY;
|
||||||
|
playlistMetadata = 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;
|
||||||
@ -656,14 +659,19 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MediaMetadata getPlaylistMetadata() {
|
public MediaMetadata getPlaylistMetadata() {
|
||||||
// CastPlayer does not currently support metadata.
|
return playlistMetadata;
|
||||||
return MediaMetadata.EMPTY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This method is not supported and does nothing. */
|
|
||||||
@Override
|
@Override
|
||||||
public void setPlaylistMetadata(MediaMetadata mediaMetadata) {
|
public void setPlaylistMetadata(MediaMetadata playlistMetadata) {
|
||||||
// CastPlayer does not currently support metadata.
|
checkNotNull(playlistMetadata);
|
||||||
|
if (playlistMetadata.equals(this.playlistMetadata)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.playlistMetadata = playlistMetadata;
|
||||||
|
listeners.sendEvent(
|
||||||
|
EVENT_PLAYLIST_METADATA_CHANGED,
|
||||||
|
listener -> listener.onPlaylistMetadataChanged(this.playlistMetadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1800,7 +1800,7 @@ public class CastPlayerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setMediaItems_doesNotifyOnMetadataChanged() {
|
public void setMediaItems_doesNotifyOnMediaMetadataChanged() {
|
||||||
when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null)))
|
when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null)))
|
||||||
.thenReturn(mockPendingResult);
|
.thenReturn(mockPendingResult);
|
||||||
ArgumentCaptor<MediaMetadata> metadataCaptor = ArgumentCaptor.forClass(MediaMetadata.class);
|
ArgumentCaptor<MediaMetadata> metadataCaptor = ArgumentCaptor.forClass(MediaMetadata.class);
|
||||||
@ -1827,7 +1827,7 @@ public class CastPlayerTest {
|
|||||||
.build());
|
.build());
|
||||||
castPlayer.addListener(mockListener);
|
castPlayer.addListener(mockListener);
|
||||||
|
|
||||||
MediaMetadata intitalMetadata = castPlayer.getMediaMetadata();
|
MediaMetadata initialMetadata = castPlayer.getMediaMetadata();
|
||||||
castPlayer.setMediaItems(firstPlaylist, /* startIndex= */ 0, /* startPositionMs= */ 2000L);
|
castPlayer.setMediaItems(firstPlaylist, /* startIndex= */ 0, /* startPositionMs= */ 2000L);
|
||||||
updateTimeLine(firstPlaylist, /* mediaQueueItemIds= */ new int[] {1}, /* currentItemId= */ 1);
|
updateTimeLine(firstPlaylist, /* mediaQueueItemIds= */ new int[] {1}, /* currentItemId= */ 1);
|
||||||
MediaMetadata firstMetadata = castPlayer.getMediaMetadata();
|
MediaMetadata firstMetadata = castPlayer.getMediaMetadata();
|
||||||
@ -1850,7 +1850,7 @@ public class CastPlayerTest {
|
|||||||
secondPlaylist.get(1).mediaMetadata,
|
secondPlaylist.get(1).mediaMetadata,
|
||||||
secondPlaylist.get(0).mediaMetadata)
|
secondPlaylist.get(0).mediaMetadata)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
assertThat(intitalMetadata).isEqualTo(MediaMetadata.EMPTY);
|
assertThat(initialMetadata).isEqualTo(MediaMetadata.EMPTY);
|
||||||
assertThat(ImmutableList.of(firstMetadata, secondMetadata, thirdMetadata))
|
assertThat(ImmutableList.of(firstMetadata, secondMetadata, thirdMetadata))
|
||||||
.containsExactly(
|
.containsExactly(
|
||||||
firstPlaylist.get(0).mediaMetadata,
|
firstPlaylist.get(0).mediaMetadata,
|
||||||
@ -1898,6 +1898,35 @@ public class CastPlayerTest {
|
|||||||
verify(mockListener, never()).onMediaMetadataChanged(any());
|
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
|
@Test
|
||||||
public void getDeviceInfo_returnsCorrectDeviceInfoWithPlaybackTypeRemote() {
|
public void getDeviceInfo_returnsCorrectDeviceInfoWithPlaybackTypeRemote() {
|
||||||
DeviceInfo deviceInfo = castPlayer.getDeviceInfo();
|
DeviceInfo deviceInfo = castPlayer.getDeviceInfo();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user