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() {