diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 933615fcf0..52d85073d3 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -26,6 +26,8 @@ * Add `MediaItem.RequestMetadata` to represent metadata needed to play media when the exact `LocalConfiguration` is not known. Also remove `MediaMetadata.mediaUrl` as this is now included in `RequestMetadata`. + * Add `Player.Command.COMMAND_SET_MEDIA_ITEM` to enable players to allow + setting a single item. * Track selection: * Flatten `TrackSelectionOverrides` class into `TrackSelectionParameters`, and promote `TrackSelectionOverride` to a top level class. diff --git a/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java b/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java index ad21e461e7..b01ff7345f 100644 --- a/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java +++ b/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java @@ -102,7 +102,8 @@ public final class CastPlayer extends BasePlayer { COMMAND_GET_MEDIA_ITEMS_METADATA, COMMAND_SET_MEDIA_ITEMS_METADATA, COMMAND_CHANGE_MEDIA_ITEMS, - COMMAND_GET_TRACKS) + COMMAND_GET_TRACKS, + COMMAND_SET_MEDIA_ITEM) .build(); public static final float MIN_SPEED_SUPPORTED = 0.5f; diff --git a/libraries/cast/src/test/java/androidx/media3/cast/CastPlayerTest.java b/libraries/cast/src/test/java/androidx/media3/cast/CastPlayerTest.java index bdc324e553..31b7afd87a 100644 --- a/libraries/cast/src/test/java/androidx/media3/cast/CastPlayerTest.java +++ b/libraries/cast/src/test/java/androidx/media3/cast/CastPlayerTest.java @@ -36,6 +36,7 @@ import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS; import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SET_DEVICE_VOLUME; +import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEMS_METADATA; import static androidx.media3.common.Player.COMMAND_SET_REPEAT_MODE; import static androidx.media3.common.Player.COMMAND_SET_SHUFFLE_MODE; @@ -1359,6 +1360,7 @@ public class CastPlayerTest { assertThat(castPlayer.isCommandAvailable(COMMAND_GET_MEDIA_ITEMS_METADATA)).isTrue(); assertThat(castPlayer.isCommandAvailable(COMMAND_SET_MEDIA_ITEMS_METADATA)).isTrue(); assertThat(castPlayer.isCommandAvailable(COMMAND_CHANGE_MEDIA_ITEMS)).isTrue(); + assertThat(castPlayer.isCommandAvailable(COMMAND_SET_MEDIA_ITEM)).isTrue(); assertThat(castPlayer.isCommandAvailable(COMMAND_GET_AUDIO_ATTRIBUTES)).isFalse(); assertThat(castPlayer.isCommandAvailable(COMMAND_GET_VOLUME)).isFalse(); assertThat(castPlayer.isCommandAvailable(COMMAND_GET_DEVICE_VOLUME)).isFalse(); diff --git a/libraries/common/src/main/java/androidx/media3/common/Player.java b/libraries/common/src/main/java/androidx/media3/common/Player.java index 4a414f6b37..8cd90d2da1 100644 --- a/libraries/common/src/main/java/androidx/media3/common/Player.java +++ b/libraries/common/src/main/java/androidx/media3/common/Player.java @@ -384,6 +384,7 @@ public interface Player { COMMAND_GET_TEXT, COMMAND_SET_TRACK_SELECTION_PARAMETERS, COMMAND_GET_TRACKS, + COMMAND_SET_MEDIA_ITEM, }; private final FlagSet.Builder flagsBuilder; @@ -1402,7 +1403,8 @@ public interface Player { * #COMMAND_GET_VOLUME}, {@link #COMMAND_GET_DEVICE_VOLUME}, {@link #COMMAND_SET_VOLUME}, {@link * #COMMAND_SET_DEVICE_VOLUME}, {@link #COMMAND_ADJUST_DEVICE_VOLUME}, {@link * #COMMAND_SET_VIDEO_SURFACE}, {@link #COMMAND_GET_TEXT}, {@link - * #COMMAND_SET_TRACK_SELECTION_PARAMETERS} or {@link #COMMAND_GET_TRACKS}. + * #COMMAND_SET_TRACK_SELECTION_PARAMETERS}, {@link #COMMAND_GET_TRACKS} or {@link + * #COMMAND_SET_MEDIA_ITEM}. */ // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility // with Kotlin usages from before TYPE_USE was added. @@ -1441,6 +1443,7 @@ public interface Player { COMMAND_GET_TEXT, COMMAND_SET_TRACK_SELECTION_PARAMETERS, COMMAND_GET_TRACKS, + COMMAND_SET_MEDIA_ITEM, }) @interface Command {} /** Command to start, pause or resume playback. */ @@ -1520,6 +1523,8 @@ public interface Player { int COMMAND_SET_TRACK_SELECTION_PARAMETERS = 29; /** Command to get details of the current track selection. */ int COMMAND_GET_TRACKS = 30; + /** Command to set a {@link MediaItem MediaItem}. */ + int COMMAND_SET_MEDIA_ITEM = 31; /** Represents an invalid {@link Command}. */ int COMMAND_INVALID = -1; diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java index 8902e5d76f..9f8cd262e5 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java @@ -303,7 +303,8 @@ import java.util.concurrent.TimeoutException; COMMAND_SET_DEVICE_VOLUME, COMMAND_ADJUST_DEVICE_VOLUME, COMMAND_SET_VIDEO_SURFACE, - COMMAND_GET_TEXT) + COMMAND_GET_TEXT, + COMMAND_SET_MEDIA_ITEM) .addIf( COMMAND_SET_TRACK_SELECTION_PARAMETERS, trackSelector.isSetParametersSupported()) .build(); diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java index 4b6ce27fc9..784f6c23df 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java @@ -37,6 +37,7 @@ import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS; import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SET_DEVICE_VOLUME; +import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEMS_METADATA; import static androidx.media3.common.Player.COMMAND_SET_REPEAT_MODE; import static androidx.media3.common.Player.COMMAND_SET_SHUFFLE_MODE; @@ -8979,6 +8980,7 @@ public final class ExoPlayerTest { assertThat(player.isCommandAvailable(COMMAND_GET_MEDIA_ITEMS_METADATA)).isTrue(); assertThat(player.isCommandAvailable(COMMAND_SET_MEDIA_ITEMS_METADATA)).isTrue(); assertThat(player.isCommandAvailable(COMMAND_CHANGE_MEDIA_ITEMS)).isTrue(); + assertThat(player.isCommandAvailable(COMMAND_SET_MEDIA_ITEM)).isTrue(); assertThat(player.isCommandAvailable(COMMAND_GET_AUDIO_ATTRIBUTES)).isTrue(); assertThat(player.isCommandAvailable(COMMAND_GET_VOLUME)).isTrue(); assertThat(player.isCommandAvailable(COMMAND_GET_DEVICE_VOLUME)).isTrue(); @@ -12128,6 +12130,7 @@ public final class ExoPlayerTest { COMMAND_GET_MEDIA_ITEMS_METADATA, COMMAND_SET_MEDIA_ITEMS_METADATA, COMMAND_CHANGE_MEDIA_ITEMS, + COMMAND_SET_MEDIA_ITEM, COMMAND_GET_AUDIO_ATTRIBUTES, COMMAND_GET_VOLUME, COMMAND_GET_DEVICE_VOLUME, diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java index 9fe1017622..6eb5406951 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java @@ -29,6 +29,7 @@ import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS; import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SET_DEVICE_VOLUME; +import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEMS_METADATA; import static androidx.media3.common.Player.COMMAND_SET_REPEAT_MODE; import static androidx.media3.common.Player.COMMAND_SET_SHUFFLE_MODE; @@ -817,12 +818,12 @@ import org.checkerframework.checker.nullness.qual.NonNull; @Override public void setMediaItem(MediaItem mediaItem) { - if (!isPlayerCommandAvailable(COMMAND_CHANGE_MEDIA_ITEMS)) { + if (!isPlayerCommandAvailable(COMMAND_SET_MEDIA_ITEM)) { return; } dispatchRemoteSessionTaskWithPlayerCommand( - COMMAND_CHANGE_MEDIA_ITEMS, + COMMAND_SET_MEDIA_ITEM, (iSession, seq) -> iSession.setMediaItem(controllerStub, seq, mediaItem.toBundle())); setMediaItemsInternal( @@ -834,12 +835,12 @@ import org.checkerframework.checker.nullness.qual.NonNull; @Override public void setMediaItem(MediaItem mediaItem, long startPositionMs) { - if (!isPlayerCommandAvailable(COMMAND_CHANGE_MEDIA_ITEMS)) { + if (!isPlayerCommandAvailable(COMMAND_SET_MEDIA_ITEM)) { return; } dispatchRemoteSessionTaskWithPlayerCommand( - COMMAND_CHANGE_MEDIA_ITEMS, + COMMAND_SET_MEDIA_ITEM, (iSession, seq) -> iSession.setMediaItemWithStartPosition( controllerStub, seq, mediaItem.toBundle(), startPositionMs)); @@ -853,12 +854,12 @@ import org.checkerframework.checker.nullness.qual.NonNull; @Override public void setMediaItem(MediaItem mediaItem, boolean resetPosition) { - if (!isPlayerCommandAvailable(COMMAND_CHANGE_MEDIA_ITEMS)) { + if (!isPlayerCommandAvailable(COMMAND_SET_MEDIA_ITEM)) { return; } dispatchRemoteSessionTaskWithPlayerCommand( - COMMAND_CHANGE_MEDIA_ITEMS, + COMMAND_SET_MEDIA_ITEM, (iSession, seq) -> iSession.setMediaItemWithResetPosition( controllerStub, seq, mediaItem.toBundle(), resetPosition)); diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSession.java b/libraries/session/src/main/java/androidx/media3/session/MediaSession.java index 93816b33fd..194f074264 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSession.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSession.java @@ -889,32 +889,6 @@ public class MediaSession { * @param controller The controller information. * @param playerCommand A {@link Player.Command command}. * @return {@link SessionResult#RESULT_SUCCESS} to proceed, or another code to ignore. - * @see Player.Command#COMMAND_PLAY_PAUSE - * @see Player.Command#COMMAND_PREPARE - * @see Player.Command#COMMAND_STOP - * @see Player.Command#COMMAND_SEEK_TO_DEFAULT_POSITION - * @see Player.Command#COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM - * @see Player.Command#COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM - * @see Player.Command#COMMAND_SEEK_TO_NEXT_MEDIA_ITEM - * @see Player.Command#COMMAND_SEEK_TO_MEDIA_ITEM - * @see Player.Command#COMMAND_SET_SPEED_AND_PITCH - * @see Player.Command#COMMAND_SET_SHUFFLE_MODE - * @see Player.Command#COMMAND_SET_REPEAT_MODE - * @see Player.Command#COMMAND_GET_CURRENT_MEDIA_ITEM - * @see Player.Command#COMMAND_GET_TIMELINE - * @see Player.Command#COMMAND_GET_MEDIA_ITEMS_METADATA - * @see Player.Command#COMMAND_SET_MEDIA_ITEMS_METADATA - * @see Player.Command#COMMAND_CHANGE_MEDIA_ITEMS - * @see Player.Command#COMMAND_GET_AUDIO_ATTRIBUTES - * @see Player.Command#COMMAND_GET_VOLUME - * @see Player.Command#COMMAND_GET_DEVICE_VOLUME - * @see Player.Command#COMMAND_SET_VOLUME - * @see Player.Command#COMMAND_SET_DEVICE_VOLUME - * @see Player.Command#COMMAND_ADJUST_DEVICE_VOLUME - * @see Player.Command#COMMAND_SET_VIDEO_SURFACE - * @see Player.Command#COMMAND_GET_TEXT - * @see Player.Command#COMMAND_SET_TRACK_SELECTION_PARAMETERS - * @see Player.Command#COMMAND_GET_TRACKS */ default @SessionResult.Code int onPlayerCommandRequest( MediaSession session, ControllerInfo controller, @Player.Command int playerCommand) { diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionLegacyStub.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionLegacyStub.java index 9dcd3bcfa9..1b84511f87 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionLegacyStub.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionLegacyStub.java @@ -24,6 +24,7 @@ import static androidx.media3.common.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SEEK_TO_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT; import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS; +import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SET_REPEAT_MODE; import static androidx.media3.common.Player.COMMAND_SET_SHUFFLE_MODE; import static androidx.media3.common.Player.COMMAND_SET_SPEED_AND_PITCH; @@ -679,7 +680,7 @@ import org.checkerframework.checker.initialization.qual.Initialized; private void handleMediaRequest(MediaItem mediaItem, boolean play) { dispatchSessionTaskWithPlayerCommand( - COMMAND_CHANGE_MEDIA_ITEMS, + COMMAND_SET_MEDIA_ITEM, controller -> { ListenableFuture> mediaItemsFuture = sessionImpl.onAddMediaItemsOnHandler(controller, ImmutableList.of(mediaItem)); diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java index 2a8bbb8b59..109d6afc1d 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java @@ -29,6 +29,7 @@ import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS; import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SET_DEVICE_VOLUME; +import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEMS_METADATA; import static androidx.media3.common.Player.COMMAND_SET_REPEAT_MODE; import static androidx.media3.common.Player.COMMAND_SET_SHUFFLE_MODE; @@ -846,7 +847,7 @@ import java.util.concurrent.ExecutionException; dispatchSessionTaskWithPlayerCommand( caller, seq, - COMMAND_CHANGE_MEDIA_ITEMS, + COMMAND_SET_MEDIA_ITEM, (sessionImpl, controller) -> sessionImpl.onAddMediaItemsOnHandler(controller, ImmutableList.of(mediaItem)), (sessionImpl, controller, sequence, future) -> @@ -873,7 +874,7 @@ import java.util.concurrent.ExecutionException; dispatchSessionTaskWithPlayerCommand( caller, seq, - COMMAND_CHANGE_MEDIA_ITEMS, + COMMAND_SET_MEDIA_ITEM, (sessionImpl, controller) -> sessionImpl.onAddMediaItemsOnHandler(controller, ImmutableList.of(mediaItem)), (sessionImpl, controller, sequence, future) -> @@ -905,7 +906,7 @@ import java.util.concurrent.ExecutionException; dispatchSessionTaskWithPlayerCommand( caller, seq, - COMMAND_CHANGE_MEDIA_ITEMS, + COMMAND_SET_MEDIA_ITEM, (sessionImpl, controller) -> sessionImpl.onAddMediaItemsOnHandler(controller, ImmutableList.of(mediaItem)), (sessionImpl, controller, sequence, future) -> diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionPermissionTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionPermissionTest.java index 0402c9f05b..80a61f8d12 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionPermissionTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionPermissionTest.java @@ -22,6 +22,7 @@ import static androidx.media3.common.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SET_DEVICE_VOLUME; +import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEMS_METADATA; import static androidx.media3.common.Player.COMMAND_SET_TRACK_SELECTION_PARAMETERS; import static androidx.media3.session.MediaUtils.createPlayerCommandsWith; @@ -135,6 +136,12 @@ public class MediaSessionPermissionTest { controller -> controller.setPlaylistMetadata(MediaMetadata.EMPTY)); } + @Test + public void setMediaItem() throws Exception { + testOnCommandRequest( + COMMAND_SET_MEDIA_ITEM, controller -> controller.setMediaItem(MediaItem.EMPTY)); + } + @Test public void setMediaItems() throws Exception { testOnCommandRequest(