From 79c8b0e0f8710ca54a0d3b4c9bcd560cd2d0e85f Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 25 Jul 2023 16:29:44 +0100 Subject: [PATCH] Set correct start time for newly enabled renderers during playback We currently pass in the time at which the stream originally started, but newly enabled renderers should get the current playback position instead. PiperOrigin-RevId: 550894630 --- .../exoplayer/ExoPlayerImplInternal.java | 15 +++--- .../media3/exoplayer/ExoPlayerTest.java | 49 +++++++++++++++++++ 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java index e02e208bcf..c5b492f27d 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java @@ -1830,7 +1830,7 @@ import java.util.concurrent.atomic.AtomicBoolean; } } } - enableRenderers(rendererWasEnabledFlags); + enableRenderers(rendererWasEnabledFlags, /* startPositionUs= */ rendererPositionUs); } else { // Release and re-prepare/buffer periods after the one whose selection changed. queue.removeAfter(periodHolder); @@ -2558,10 +2558,13 @@ import java.util.concurrent.atomic.AtomicBoolean; } private void enableRenderers() throws ExoPlaybackException { - enableRenderers(/* rendererWasEnabledFlags= */ new boolean[renderers.length]); + enableRenderers( + /* rendererWasEnabledFlags= */ new boolean[renderers.length], + queue.getReadingPeriod().getStartPositionRendererTime()); } - private void enableRenderers(boolean[] rendererWasEnabledFlags) throws ExoPlaybackException { + private void enableRenderers(boolean[] rendererWasEnabledFlags, long startPositionUs) + throws ExoPlaybackException { MediaPeriodHolder readingMediaPeriod = queue.getReadingPeriod(); TrackSelectorResult trackSelectorResult = readingMediaPeriod.getTrackSelectorResult(); // Reset all disabled renderers before enabling any new ones. This makes sure resources released @@ -2574,13 +2577,13 @@ import java.util.concurrent.atomic.AtomicBoolean; // Enable the renderers. for (int i = 0; i < renderers.length; i++) { if (trackSelectorResult.isRendererEnabled(i)) { - enableRenderer(i, rendererWasEnabledFlags[i]); + enableRenderer(i, rendererWasEnabledFlags[i], startPositionUs); } } readingMediaPeriod.allRenderersInCorrectState = true; } - private void enableRenderer(int rendererIndex, boolean wasRendererEnabled) + private void enableRenderer(int rendererIndex, boolean wasRendererEnabled, long startPositionUs) throws ExoPlaybackException { Renderer renderer = renderers[rendererIndex]; if (isRendererEnabled(renderer)) { @@ -2607,7 +2610,7 @@ import java.util.concurrent.atomic.AtomicBoolean; rendererPositionUs, joining, mayRenderStartOfStream, - periodHolder.getStartPositionRendererTime(), + startPositionUs, periodHolder.getRendererOffset()); renderer.handleMessage( Renderer.MSG_SET_WAKEUP_LISTENER, 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 bbd205b523..ca860ab522 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java @@ -13843,6 +13843,55 @@ public final class ExoPlayerTest { verify(listener, times(2)).onPlaybackStateChanged(Player.STATE_BUFFERING); } + @Test + public void newlyEnabledRendererMidPlayback_receivesCurrentPlaybackPositionAsStartTime() + throws Exception { + AtomicLong startPositionInRendererUs = new AtomicLong(); + AtomicLong rendererOffsetUs = new AtomicLong(); + FakeRenderer newlyEnabledRenderer = + new FakeRenderer(C.TRACK_TYPE_AUDIO) { + @Override + protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) + throws ExoPlaybackException { + super.onStreamChanged(formats, startPositionUs, offsetUs); + startPositionInRendererUs.set(startPositionUs); + rendererOffsetUs.set(offsetUs); + } + }; + Timeline timeline = new FakeTimeline(); + ExoPlayer player = + new TestExoPlayerBuilder(context) + .setRenderers(new FakeRenderer(C.TRACK_TYPE_VIDEO), newlyEnabledRenderer) + .build(); + player.setTrackSelectionParameters( + player + .getTrackSelectionParameters() + .buildUpon() + .setTrackTypeDisabled(C.TRACK_TYPE_AUDIO, /* disabled= */ true) + .build()); + player.setMediaSource( + new FakeMediaSource( + timeline, ExoPlayerTestRunner.VIDEO_FORMAT, ExoPlayerTestRunner.AUDIO_FORMAT)); + player.prepare(); + + playUntilPosition(player, /* mediaItemIndex= */ 0, /* positionMs= */ 1_250); + player.setTrackSelectionParameters( + player + .getTrackSelectionParameters() + .buildUpon() + .setTrackTypeDisabled(C.TRACK_TYPE_AUDIO, /* disabled= */ false) + .build()); + player.play(); + runUntilPlaybackState(player, STATE_ENDED); + player.release(); + + long expectedStartPositionInRendererUs = + 1_250_000 + + rendererOffsetUs.get() + + timeline.getWindow(/* windowIndex= */ 0, new Window()).positionInFirstPeriodUs; + assertThat(startPositionInRendererUs.get()).isEqualTo(expectedStartPositionInRendererUs); + } + // Internal methods. private void addWatchAsSystemFeature() {