Update available commands when setting a new player in MediaSession

#minor-release

PiperOrigin-RevId: 523633865
This commit is contained in:
tonihei 2023-04-12 09:33:46 +01:00 committed by Rohit Singh
parent 7ee53219ff
commit ae875648a7
6 changed files with 43 additions and 14 deletions

View File

@ -37,6 +37,8 @@
* Add missing forwarding of `MediaSession.broadcastCustomCommand` to the * Add missing forwarding of `MediaSession.broadcastCustomCommand` to the
legacy `MediaControllerCompat.Callback.onSessionEvent` legacy `MediaControllerCompat.Callback.onSessionEvent`
([#293](https://github.com/androidx/media/issues/293)). ([#293](https://github.com/androidx/media/issues/293)).
* Fix bug where calling `MediaSession.setPlayer` doesn't update the
available commands.
* Audio: * Audio:
* Fix bug where some playbacks fail when tunneling is enabled and * Fix bug where some playbacks fail when tunneling is enabled and
`AudioProcessors` are active, e.g. for gapless trimming `AudioProcessors` are active, e.g. for gapless trimming

View File

@ -15,7 +15,6 @@
*/ */
package androidx.media3.session; package androidx.media3.session;
import static androidx.media3.common.Player.COMMAND_GET_TRACKS;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkStateNotNull; import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.common.util.Util.castNonNull; import static androidx.media3.common.util.Util.castNonNull;
@ -279,8 +278,7 @@ import org.checkerframework.checker.initialization.qual.Initialized;
} }
playerInfo = newPlayerWrapper.createPlayerInfoForBundling(); playerInfo = newPlayerWrapper.createPlayerInfoForBundling();
onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage( handleAvailablePlayerCommandsChanged(newPlayerWrapper.getAvailableCommands());
/* excludeTimeline= */ false, /* excludeTracks= */ false);
} }
public void release() { public void release() {
@ -773,6 +771,20 @@ import org.checkerframework.checker.initialization.qual.Initialized;
} }
} }
private void handleAvailablePlayerCommandsChanged(Player.Commands availableCommands) {
// Update PlayerInfo and do not force exclude elements in case they need to be updated because
// an available command has been removed.
onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
/* excludeTimeline= */ false, /* excludeTracks= */ false);
dispatchRemoteControllerTaskWithoutReturn(
(callback, seq) -> callback.onAvailableCommandsChangedFromPlayer(seq, availableCommands));
// Forcefully update playback info to update VolumeProviderCompat in case
// COMMAND_ADJUST_DEVICE_VOLUME or COMMAND_SET_DEVICE_VOLUME value has changed.
dispatchRemoteControllerTaskToLegacyStub(
(callback, seq) -> callback.onDeviceInfoChanged(seq, playerInfo.deviceInfo));
}
/* @FunctionalInterface */ /* @FunctionalInterface */
interface RemoteControllerTask { interface RemoteControllerTask {
@ -1183,16 +1195,7 @@ import org.checkerframework.checker.initialization.qual.Initialized;
if (player == null) { if (player == null) {
return; return;
} }
boolean excludeTracks = !availableCommands.contains(COMMAND_GET_TRACKS); session.handleAvailablePlayerCommandsChanged(availableCommands);
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
/* excludeTimeline= */ false, excludeTracks);
session.dispatchRemoteControllerTaskWithoutReturn(
(callback, seq) -> callback.onAvailableCommandsChangedFromPlayer(seq, availableCommands));
// Forcefully update playback info to update VolumeProviderCompat in case
// COMMAND_ADJUST_DEVICE_VOLUME or COMMAND_SET_DEVICE_VOLUME value has changed.
session.dispatchRemoteControllerTaskToLegacyStub(
(callback, seq) -> callback.onDeviceInfoChanged(seq, session.playerInfo.deviceInfo));
} }
@Override @Override

View File

@ -101,6 +101,7 @@ public class CommonConstants {
public static final String KEY_MAX_SEEK_TO_PREVIOUS_POSITION_MS = "maxSeekToPreviousPositionMs"; public static final String KEY_MAX_SEEK_TO_PREVIOUS_POSITION_MS = "maxSeekToPreviousPositionMs";
public static final String KEY_TRACK_SELECTION_PARAMETERS = "trackSelectionParameters"; public static final String KEY_TRACK_SELECTION_PARAMETERS = "trackSelectionParameters";
public static final String KEY_CURRENT_TRACKS = "currentTracks"; public static final String KEY_CURRENT_TRACKS = "currentTracks";
public static final String KEY_AVAILABLE_COMMANDS = "availableCommands";
// SessionCompat arguments // SessionCompat arguments
public static final String KEY_SESSION_COMPAT_TOKEN = "sessionCompatToken"; public static final String KEY_SESSION_COMPAT_TOKEN = "sessionCompatToken";

View File

@ -326,6 +326,8 @@ public class MediaControllerListenerTest {
@Player.RepeatMode int testRepeatMode = Player.REPEAT_MODE_ALL; @Player.RepeatMode int testRepeatMode = Player.REPEAT_MODE_ALL;
int testCurrentAdGroupIndex = 33; int testCurrentAdGroupIndex = 33;
int testCurrentAdIndexInAdGroup = 11; int testCurrentAdIndexInAdGroup = 11;
Commands testCommands =
new Commands.Builder().addAllCommands().remove(Player.COMMAND_STOP).build();
AtomicInteger stateRef = new AtomicInteger(); AtomicInteger stateRef = new AtomicInteger();
AtomicReference<Timeline> timelineRef = new AtomicReference<>(); AtomicReference<Timeline> timelineRef = new AtomicReference<>();
AtomicReference<MediaMetadata> playlistMetadataRef = new AtomicReference<>(); AtomicReference<MediaMetadata> playlistMetadataRef = new AtomicReference<>();
@ -335,7 +337,8 @@ public class MediaControllerListenerTest {
AtomicInteger currentAdIndexInAdGroupRef = new AtomicInteger(); AtomicInteger currentAdIndexInAdGroupRef = new AtomicInteger();
AtomicBoolean shuffleModeEnabledRef = new AtomicBoolean(); AtomicBoolean shuffleModeEnabledRef = new AtomicBoolean();
AtomicInteger repeatModeRef = new AtomicInteger(); AtomicInteger repeatModeRef = new AtomicInteger();
CountDownLatch latch = new CountDownLatch(7); AtomicReference<Commands> commandsRef = new AtomicReference<>();
CountDownLatch latch = new CountDownLatch(8);
MediaController controller = controllerTestRule.createController(remoteSession.getToken()); MediaController controller = controllerTestRule.createController(remoteSession.getToken());
threadTestRule threadTestRule
.getHandler() .getHandler()
@ -343,6 +346,12 @@ public class MediaControllerListenerTest {
() -> () ->
controller.addListener( controller.addListener(
new Player.Listener() { new Player.Listener() {
@Override
public void onAvailableCommandsChanged(Commands availableCommands) {
commandsRef.set(availableCommands);
latch.countDown();
}
@Override @Override
public void onAudioAttributesChanged(AudioAttributes attributes) { public void onAudioAttributesChanged(AudioAttributes attributes) {
audioAttributesRef.set(attributes); audioAttributesRef.set(attributes);
@ -402,6 +411,7 @@ public class MediaControllerListenerTest {
.setIsPlayingAd(true) .setIsPlayingAd(true)
.setCurrentAdGroupIndex(testCurrentAdGroupIndex) .setCurrentAdGroupIndex(testCurrentAdGroupIndex)
.setCurrentAdIndexInAdGroup(testCurrentAdIndexInAdGroup) .setCurrentAdIndexInAdGroup(testCurrentAdIndexInAdGroup)
.setAvailableCommands(testCommands)
.build(); .build();
remoteSession.setPlayer(playerConfig); remoteSession.setPlayer(playerConfig);
@ -415,6 +425,7 @@ public class MediaControllerListenerTest {
assertThat(currentAdIndexInAdGroupRef.get()).isEqualTo(testCurrentAdIndexInAdGroup); assertThat(currentAdIndexInAdGroupRef.get()).isEqualTo(testCurrentAdIndexInAdGroup);
assertThat(shuffleModeEnabledRef.get()).isEqualTo(testShuffleModeEnabled); assertThat(shuffleModeEnabledRef.get()).isEqualTo(testShuffleModeEnabled);
assertThat(repeatModeRef.get()).isEqualTo(testRepeatMode); assertThat(repeatModeRef.get()).isEqualTo(testRepeatMode);
assertThat(commandsRef.get()).isEqualTo(testCommands);
} }
@Test @Test

View File

@ -18,6 +18,7 @@ package androidx.media3.session;
import static androidx.media3.common.Player.COMMAND_GET_TRACKS; import static androidx.media3.common.Player.COMMAND_GET_TRACKS;
import static androidx.media3.test.session.common.CommonConstants.ACTION_MEDIA3_SESSION; import static androidx.media3.test.session.common.CommonConstants.ACTION_MEDIA3_SESSION;
import static androidx.media3.test.session.common.CommonConstants.KEY_AUDIO_ATTRIBUTES; import static androidx.media3.test.session.common.CommonConstants.KEY_AUDIO_ATTRIBUTES;
import static androidx.media3.test.session.common.CommonConstants.KEY_AVAILABLE_COMMANDS;
import static androidx.media3.test.session.common.CommonConstants.KEY_BUFFERED_PERCENTAGE; import static androidx.media3.test.session.common.CommonConstants.KEY_BUFFERED_PERCENTAGE;
import static androidx.media3.test.session.common.CommonConstants.KEY_BUFFERED_POSITION; import static androidx.media3.test.session.common.CommonConstants.KEY_BUFFERED_POSITION;
import static androidx.media3.test.session.common.CommonConstants.KEY_CONTENT_BUFFERED_POSITION; import static androidx.media3.test.session.common.CommonConstants.KEY_CONTENT_BUFFERED_POSITION;
@ -395,6 +396,10 @@ public class MediaSessionProviderService extends Service {
player.trackSelectionParameters = player.trackSelectionParameters =
TrackSelectionParameters.fromBundle(trackSelectionParametersBundle); TrackSelectionParameters.fromBundle(trackSelectionParametersBundle);
} }
@Nullable Bundle availableCommandsBundle = config.getBundle(KEY_AVAILABLE_COMMANDS);
if (availableCommandsBundle != null) {
player.commands = Player.Commands.CREATOR.fromBundle(availableCommandsBundle);
}
return player; return player;
} }

View File

@ -17,6 +17,7 @@ package androidx.media3.session;
import static androidx.media3.test.session.common.CommonConstants.ACTION_MEDIA3_SESSION; import static androidx.media3.test.session.common.CommonConstants.ACTION_MEDIA3_SESSION;
import static androidx.media3.test.session.common.CommonConstants.KEY_AUDIO_ATTRIBUTES; import static androidx.media3.test.session.common.CommonConstants.KEY_AUDIO_ATTRIBUTES;
import static androidx.media3.test.session.common.CommonConstants.KEY_AVAILABLE_COMMANDS;
import static androidx.media3.test.session.common.CommonConstants.KEY_BUFFERED_PERCENTAGE; import static androidx.media3.test.session.common.CommonConstants.KEY_BUFFERED_PERCENTAGE;
import static androidx.media3.test.session.common.CommonConstants.KEY_BUFFERED_POSITION; import static androidx.media3.test.session.common.CommonConstants.KEY_BUFFERED_POSITION;
import static androidx.media3.test.session.common.CommonConstants.KEY_CONTENT_BUFFERED_POSITION; import static androidx.media3.test.session.common.CommonConstants.KEY_CONTENT_BUFFERED_POSITION;
@ -740,6 +741,12 @@ public class RemoteMediaSession {
return this; return this;
} }
@CanIgnoreReturnValue
public MockPlayerConfigBuilder setAvailableCommands(Player.Commands availableCommands) {
bundle.putBundle(KEY_AVAILABLE_COMMANDS, availableCommands.toBundle());
return this;
}
public Bundle build() { public Bundle build() {
return bundle; return bundle;
} }