From 2186b6d325c531fa992c78f018eb38fe86e84c66 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 19 Dec 2022 08:41:50 +0000 Subject: [PATCH] Avoid sending periodic position updates while paused and not loading The period updates were introduced to ensure the buffered position is updated regularly and that any playback position drift is corrected. None of these updates need to happen while the player is paused or not loading and we can avoid the constant binder interactions. PiperOrigin-RevId: 496329800 (cherry picked from commit 0749b05923dd733bb515920334a9aae6067a072f) --- .../media3/session/MediaSessionImpl.java | 23 +++++++---- .../media3/session/MediaControllerTest.java | 39 +++++++++++++++++-- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java index d01fb6eee3..4e075c18bd 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java @@ -121,6 +121,7 @@ import org.checkerframework.checker.initialization.qual.Initialized; @Nullable private final BroadcastReceiver broadcastReceiver; private final Handler applicationHandler; private final BitmapLoader bitmapLoader; + private final Runnable periodicSessionPositionInfoUpdateRunnable; @Nullable private PlayerListener playerListener; @Nullable private MediaSession.Listener mediaSessionListener; @@ -246,8 +247,9 @@ import org.checkerframework.checker.initialization.qual.Initialized; /* oldPlayerWrapper= */ null, /* newPlayerWrapper= */ playerWrapper)); sessionPositionUpdateDelayMs = DEFAULT_SESSION_POSITION_UPDATE_DELAY_MS; - applicationHandler.postDelayed( - thisRef::notifyPeriodicSessionPositionInfoChangesOnHandler, sessionPositionUpdateDelayMs); + periodicSessionPositionInfoUpdateRunnable = + thisRef::notifyPeriodicSessionPositionInfoChangesOnHandler; + postOrRun(applicationHandler, thisRef::schedulePeriodicSessionPositionInfoChanges); } public void setPlayer(Player player) { @@ -567,10 +569,7 @@ import org.checkerframework.checker.initialization.qual.Initialized; protected void setSessionPositionUpdateDelayMsOnHandler(long updateDelayMs) { verifyApplicationThread(); sessionPositionUpdateDelayMs = updateDelayMs; - - applicationHandler.removeCallbacks(this::notifyPeriodicSessionPositionInfoChangesOnHandler); - applicationHandler.postDelayed( - this::notifyPeriodicSessionPositionInfoChangesOnHandler, updateDelayMs); + schedulePeriodicSessionPositionInfoChanges(); } @Nullable @@ -718,9 +717,15 @@ import org.checkerframework.checker.initialization.qual.Initialized; SessionPositionInfo sessionPositionInfo = playerWrapper.createSessionPositionInfoForBundling(); dispatchRemoteControllerTaskWithoutReturn( (callback, seq) -> callback.onPeriodicSessionPositionInfoChanged(seq, sessionPositionInfo)); - if (sessionPositionUpdateDelayMs > 0) { + schedulePeriodicSessionPositionInfoChanges(); + } + + private void schedulePeriodicSessionPositionInfoChanges() { + applicationHandler.removeCallbacks(periodicSessionPositionInfoUpdateRunnable); + if (sessionPositionUpdateDelayMs > 0 + && (playerWrapper.isPlaying() || playerWrapper.isLoading())) { applicationHandler.postDelayed( - this::notifyPeriodicSessionPositionInfoChangesOnHandler, sessionPositionUpdateDelayMs); + periodicSessionPositionInfoUpdateRunnable, sessionPositionUpdateDelayMs); } } @@ -859,6 +864,7 @@ import org.checkerframework.checker.initialization.qual.Initialized; /* excludeTimeline= */ true, /* excludeTracks= */ true); session.dispatchRemoteControllerTaskToLegacyStub( (callback, seq) -> callback.onIsPlayingChanged(seq, isPlaying)); + session.schedulePeriodicSessionPositionInfoChanges(); } @Override @@ -877,6 +883,7 @@ import org.checkerframework.checker.initialization.qual.Initialized; /* excludeTimeline= */ true, /* excludeTracks= */ true); session.dispatchRemoteControllerTaskToLegacyStub( (callback, seq) -> callback.onIsLoadingChanged(seq, isLoading)); + session.schedulePeriodicSessionPositionInfoChanges(); } @Override diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerTest.java index 3c13e756ce..a7b5dbfc6c 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerTest.java @@ -24,6 +24,7 @@ import static androidx.media3.test.session.common.MediaSessionConstants.KEY_AVAI import static androidx.media3.test.session.common.MediaSessionConstants.TEST_GET_SESSION_ACTIVITY; import static androidx.media3.test.session.common.MediaSessionConstants.TEST_IS_SESSION_COMMAND_AVAILABLE; import static androidx.media3.test.session.common.TestUtils.LONG_TIMEOUT_MS; +import static androidx.media3.test.session.common.TestUtils.NO_RESPONSE_TIMEOUT_MS; import static androidx.media3.test.session.common.TestUtils.TIMEOUT_MS; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; @@ -984,11 +985,18 @@ public class MediaControllerTest { @Test public void getBufferedPosition_withPeriodicUpdate_updatedWithoutCallback() throws Exception { long testBufferedPosition = 999L; + Bundle playerConfig = + new RemoteMediaSession.MockPlayerConfigBuilder() + .setPlayWhenReady(true) + .setPlaybackSuppressionReason(Player.PLAYBACK_SUPPRESSION_REASON_NONE) + .setPlaybackState(Player.STATE_READY) + .setIsLoading(true) + .build(); + remoteSession.setPlayer(playerConfig); MediaController controller = controllerTestRule.createController(remoteSession.getToken()); + remoteSession.setSessionPositionUpdateDelayMs(10L); + remoteSession.getMockPlayer().setBufferedPosition(testBufferedPosition); - - remoteSession.setSessionPositionUpdateDelayMs(0L); - PollingCheck.waitFor( TIMEOUT_MS, () -> { @@ -998,6 +1006,31 @@ public class MediaControllerTest { }); } + @Test + public void getBufferedPosition_whilePausedAndNotLoading_isNotUpdatedPeriodically() + throws Exception { + long testBufferedPosition = 999L; + Bundle playerConfig = + new RemoteMediaSession.MockPlayerConfigBuilder() + .setPlayWhenReady(false) + .setPlaybackSuppressionReason(Player.PLAYBACK_SUPPRESSION_REASON_NONE) + .setPlaybackState(Player.STATE_READY) + .setIsLoading(false) + .build(); + remoteSession.setPlayer(playerConfig); + MediaController controller = controllerTestRule.createController(remoteSession.getToken()); + remoteSession.setSessionPositionUpdateDelayMs(10L); + + remoteSession.getMockPlayer().setBufferedPosition(testBufferedPosition); + Thread.sleep(NO_RESPONSE_TIMEOUT_MS); + AtomicLong bufferedPositionAfterDelay = new AtomicLong(); + threadTestRule + .getHandler() + .postAndSync(() -> bufferedPositionAfterDelay.set(controller.getBufferedPosition())); + + assertThat(bufferedPositionAfterDelay.get()).isNotEqualTo(testBufferedPosition); + } + @Test public void getContentBufferedPosition_byDefault_returnsZero() throws Exception { MediaController controller = controllerTestRule.createController(remoteSession.getToken());