From 0fbe083d4ec81e4482f8cdbe6cb53f6bc6173ecb Mon Sep 17 00:00:00 2001 From: hoangtc Date: Wed, 1 Aug 2018 05:28:29 -0700 Subject: [PATCH] Return empty track groups and track selections when user seeks to unprepared period When user seeks to an unprepared period, since there is no period being played, currently the track groups and track selections are still the ones from previous period. This CL changes it so that when such seeking happens, PlaybackInfo's track groups and track selections are changed to empty. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=206916109 --- .../android/exoplayer2/ExoPlayerImpl.java | 9 ++- .../exoplayer2/ExoPlayerImplInternal.java | 3 + .../android/exoplayer2/ExoPlayerTest.java | 56 +++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 0435d221fe..dcc88fc453 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -47,9 +47,16 @@ import java.util.concurrent.CopyOnWriteArraySet; private static final String TAG = "ExoPlayerImpl"; + /** + * This empty track selector result can only be used for {@link PlaybackInfo#trackSelectorResult} + * when the player does not have any track selection made (such as when player is reset, or when + * player seeks to an unprepared period). It will not be used as result of any {@link + * TrackSelector#selectTracks(RendererCapabilities[], TrackGroupArray)} operation. + */ + /* package */ final TrackSelectorResult emptyTrackSelectorResult; + private final Renderer[] renderers; private final TrackSelector trackSelector; - private final TrackSelectorResult emptyTrackSelectorResult; private final Handler eventHandler; private final ExoPlayerImplInternal internalPlayer; private final Handler internalPlayerHandler; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 03a42deec1..7e54726daf 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -700,6 +700,9 @@ import java.util.Collections; maybeContinueLoading(); } else { queue.clear(/* keepFrontPeriodUid= */ true); + // New period has not been prepared. + playbackInfo = + playbackInfo.copyWithTrackInfo(TrackGroupArray.EMPTY, emptyTrackSelectorResult); resetRendererPosition(periodPositionUs); } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java index e28fdd18a3..1e676f2123 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -29,6 +29,7 @@ import com.google.android.exoplayer2.source.ConcatenatingMediaSource; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; +import com.google.android.exoplayer2.source.ShuffleOrder; import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.ads.AdPlaybackState; @@ -48,6 +49,8 @@ import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinit import com.google.android.exoplayer2.testutil.FakeTrackSelection; import com.google.android.exoplayer2.testutil.FakeTrackSelector; import com.google.android.exoplayer2.testutil.RobolectricUtil; +import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.util.Clock; @@ -2288,6 +2291,59 @@ public final class ExoPlayerTest { .isAtLeast(C.usToMs(expectedDurationUs)); } + @Test + public void testUpdateTrackSelectorThenSeekToUnpreparedPeriod_returnsEmptyTrackGroups() + throws Exception { + Timeline fakeTimeline = new FakeTimeline(/* windowCount= */ 1); + MediaSource[] fakeMediaSources = { + new FakeMediaSource(fakeTimeline, null, Builder.VIDEO_FORMAT), + new FakeMediaSource(fakeTimeline, null, Builder.AUDIO_FORMAT) + }; + MediaSource mediaSource = + new ConcatenatingMediaSource( + /* isAtomic= */ false, + /* useLazyPreparation= */ true, + new ShuffleOrder.DefaultShuffleOrder(0), + fakeMediaSources); + FakeRenderer renderer = new FakeRenderer(Builder.VIDEO_FORMAT); + DefaultTrackSelector trackSelector = new DefaultTrackSelector(); + ActionSchedule actionSchedule = + new ActionSchedule.Builder("testSendMessages") + .pause() + .waitForPlaybackState(Player.STATE_READY) + .seek(/* windowIndex= */ 1, /* positionMs= */ 0) + .play() + .build(); + List trackGroupsList = new ArrayList<>(); + List trackSelectionsList = new ArrayList<>(); + new Builder() + .setMediaSource(mediaSource) + .setTrackSelector(trackSelector) + .setRenderers(renderer) + .setActionSchedule(actionSchedule) + .setEventListener( + new EventListener() { + @Override + public void onTracksChanged( + TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { + trackGroupsList.add(trackGroups); + trackSelectionsList.add(trackSelections); + } + }) + .build(context) + .start() + .blockUntilEnded(TIMEOUT_MS); + assertThat(trackGroupsList).hasSize(3); + // First track groups of the 1st period are reported. + // Then the seek to an unprepared period will result in empty track groups and selections being + // returned. + // Then the track groups of the 2nd period are reported. + assertThat(trackGroupsList.get(0).get(0).getFormat(0)).isEqualTo(Builder.VIDEO_FORMAT); + assertThat(trackGroupsList.get(1)).isEqualTo(TrackGroupArray.EMPTY); + assertThat(trackSelectionsList.get(1).get(0)).isNull(); + assertThat(trackGroupsList.get(2).get(0).getFormat(0)).isEqualTo(Builder.AUDIO_FORMAT); + } + // Internal methods. private static ActionSchedule.Builder addSurfaceSwitch(ActionSchedule.Builder builder) {