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
This commit is contained in:
hoangtc 2018-08-01 05:28:29 -07:00 committed by Oliver Woodman
parent 45c1e9eef3
commit 0fbe083d4e
3 changed files with 67 additions and 1 deletions

View File

@ -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;

View File

@ -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);
}

View File

@ -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<TrackGroupArray> trackGroupsList = new ArrayList<>();
List<TrackSelectionArray> 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) {