From 036a28b292c391ff3c262fabda153e08e3c9edcc Mon Sep 17 00:00:00 2001 From: christosts Date: Thu, 23 Dec 2021 14:51:17 +0000 Subject: [PATCH] MediaController: stop advancing content position when player is paused MediaController.getContentPosition() estimates the content position based on the last position info sent by the player and the elapsed real-time since the position info was received. After calling MediaController's play/pause/setPlayWhenReady, the position estimation logic is still applying, therefore advancing the position until the underlying player's actual position is received. This can make the MediaController's content position to be out of sync with player's actual content position. With this change, MediaController stops making content position estimations after any of play/pause/setPlayWhenReady is called and until a new position info is received from the underlying player. Tested manually with the the session demo app, pausing/resuming content from the UI. PiperOrigin-RevId: 418000800 --- .../session/MediaControllerImplBase.java | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) 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 51a8008f5d..47d07b71e2 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java @@ -186,6 +186,8 @@ import org.checkerframework.checker.nullness.qual.NonNull; private int surfaceWidth; private int surfaceHeight; @Nullable private IMediaSession iSession; + private long lastReturnedContentPositionMs; + private long lastSetPlayWhenReadyCalledTimeMs; public MediaControllerImplBase( Context context, MediaController instance, SessionToken token, Bundle connectionHints) { @@ -228,6 +230,8 @@ import org.checkerframework.checker.nullness.qual.NonNull; this.instance.runOnApplicationLooper(MediaControllerImplBase.this.instance::release); } flushCommandQueueHandler = new FlushCommandQueueHandler(instance.getApplicationLooper()); + lastReturnedContentPositionMs = C.TIME_UNSET; + lastSetPlayWhenReadyCalledTimeMs = C.TIME_UNSET; } @Override @@ -662,9 +666,22 @@ import org.checkerframework.checker.nullness.qual.NonNull; @Override public long getContentPosition() { + boolean receivedUpdatedPositionInfo = + lastSetPlayWhenReadyCalledTimeMs != C.TIME_UNSET + && lastSetPlayWhenReadyCalledTimeMs < playerInfo.sessionPositionInfo.eventTimeMs; if (!playerInfo.isPlaying || playerInfo.sessionPositionInfo.isPlayingAd) { - return playerInfo.sessionPositionInfo.positionInfo.contentPositionMs; + if (receivedUpdatedPositionInfo || lastReturnedContentPositionMs == C.TIME_UNSET) { + lastReturnedContentPositionMs = + playerInfo.sessionPositionInfo.positionInfo.contentPositionMs; + } + return lastReturnedContentPositionMs; } + + if (!receivedUpdatedPositionInfo && lastReturnedContentPositionMs != C.TIME_UNSET) { + // We need an updated content position to make a new position estimation. + return lastReturnedContentPositionMs; + } + long elapsedTimeMs = (instance.getTimeDiffMs() != C.TIME_UNSET) ? instance.getTimeDiffMs() @@ -672,9 +689,12 @@ import org.checkerframework.checker.nullness.qual.NonNull; long estimatedPositionMs = playerInfo.sessionPositionInfo.positionInfo.contentPositionMs + (long) (elapsedTimeMs * playerInfo.playbackParameters.speed); - return playerInfo.sessionPositionInfo.contentDurationMs == C.TIME_UNSET - ? estimatedPositionMs - : Math.min(estimatedPositionMs, playerInfo.sessionPositionInfo.contentDurationMs); + if (playerInfo.sessionPositionInfo.contentDurationMs != C.TIME_UNSET) { + estimatedPositionMs = + Math.min(estimatedPositionMs, playerInfo.sessionPositionInfo.contentDurationMs); + } + lastReturnedContentPositionMs = estimatedPositionMs; + return lastReturnedContentPositionMs; } @Override @@ -2051,6 +2071,9 @@ import org.checkerframework.checker.nullness.qual.NonNull; && playerInfo.playbackSuppressionReason == playbackSuppressionReason) { return; } + + // Stop estimating content position until a new positionInfo arrives from the player + lastSetPlayWhenReadyCalledTimeMs = SystemClock.elapsedRealtime(); PlayerInfo playerInfo = this.playerInfo.copyWithPlayWhenReady( playWhenReady, playWhenReadyChangeReason, playbackSuppressionReason);