mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Make current period a placeholder when a live stream is reset
In case the player is reset while a live stream is playing, the current period needs to be a placeholder. This makes sure that the default start position is used when the first live timeline arrives after re-preparing. #minor-release PiperOrigin-RevId: 539044360 (cherry picked from commit 71153a43a8e55380076af97450414f9142dc636b)
This commit is contained in:
parent
50f4caacd6
commit
56c62d1ab1
@ -1492,9 +1492,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
queue.clear();
|
||||
shouldContinueLoading = false;
|
||||
|
||||
Timeline timeline = playbackInfo.timeline;
|
||||
if (releaseMediaSourceList && timeline instanceof PlaylistTimeline) {
|
||||
// Wrap the current live timeline to make sure the current period is marked as a placeholder
|
||||
// to force resolving the default start position with the next timeline refresh.
|
||||
timeline =
|
||||
((PlaylistTimeline) playbackInfo.timeline)
|
||||
.copyWithPlaceholderTimeline(mediaSourceList.getShuffleOrder());
|
||||
}
|
||||
playbackInfo =
|
||||
new PlaybackInfo(
|
||||
playbackInfo.timeline,
|
||||
timeline,
|
||||
mediaPeriodId,
|
||||
requestedContentPositionUs,
|
||||
/* discontinuityStartPositionUs= */ startPositionUs,
|
||||
|
@ -365,6 +365,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
return new PlaylistTimeline(mediaSourceHolders, shuffleOrder);
|
||||
}
|
||||
|
||||
/** Returns the shuffle order */
|
||||
public ShuffleOrder getShuffleOrder() {
|
||||
return shuffleOrder;
|
||||
}
|
||||
|
||||
// Internal methods.
|
||||
|
||||
private void enableMediaSource(MediaSourceHolder mediaSourceHolder) {
|
||||
|
@ -18,6 +18,7 @@ package androidx.media3.exoplayer;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Timeline;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.exoplayer.source.ForwardingTimeline;
|
||||
import androidx.media3.exoplayer.source.ShuffleOrder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -39,23 +40,26 @@ import java.util.List;
|
||||
public PlaylistTimeline(
|
||||
Collection<? extends MediaSourceInfoHolder> mediaSourceInfoHolders,
|
||||
ShuffleOrder shuffleOrder) {
|
||||
this(getTimelines(mediaSourceInfoHolders), getUids(mediaSourceInfoHolders), shuffleOrder);
|
||||
}
|
||||
|
||||
private PlaylistTimeline(Timeline[] timelines, Object[] uids, ShuffleOrder shuffleOrder) {
|
||||
super(/* isAtomic= */ false, shuffleOrder);
|
||||
int childCount = mediaSourceInfoHolders.size();
|
||||
int childCount = timelines.length;
|
||||
this.timelines = timelines;
|
||||
firstPeriodInChildIndices = new int[childCount];
|
||||
firstWindowInChildIndices = new int[childCount];
|
||||
timelines = new Timeline[childCount];
|
||||
uids = new Object[childCount];
|
||||
this.uids = uids;
|
||||
childIndexByUid = new HashMap<>();
|
||||
int index = 0;
|
||||
int windowCount = 0;
|
||||
int periodCount = 0;
|
||||
for (MediaSourceInfoHolder mediaSourceInfoHolder : mediaSourceInfoHolders) {
|
||||
timelines[index] = mediaSourceInfoHolder.getTimeline();
|
||||
for (Timeline timeline : timelines) {
|
||||
this.timelines[index] = timeline;
|
||||
firstWindowInChildIndices[index] = windowCount;
|
||||
firstPeriodInChildIndices[index] = periodCount;
|
||||
windowCount += timelines[index].getWindowCount();
|
||||
periodCount += timelines[index].getPeriodCount();
|
||||
uids[index] = mediaSourceInfoHolder.getUid();
|
||||
windowCount += this.timelines[index].getWindowCount();
|
||||
periodCount += this.timelines[index].getPeriodCount();
|
||||
childIndexByUid.put(uids[index], index++);
|
||||
}
|
||||
this.windowCount = windowCount;
|
||||
@ -112,4 +116,40 @@ import java.util.List;
|
||||
public int getPeriodCount() {
|
||||
return periodCount;
|
||||
}
|
||||
|
||||
public PlaylistTimeline copyWithPlaceholderTimeline(ShuffleOrder shuffleOrder) {
|
||||
Timeline[] newTimelines = new Timeline[timelines.length];
|
||||
for (int i = 0; i < timelines.length; i++) {
|
||||
newTimelines[i] =
|
||||
new ForwardingTimeline(timelines[i]) {
|
||||
@Override
|
||||
public Period getPeriod(int periodIndex, Period period, boolean setIds) {
|
||||
Period superPeriod = super.getPeriod(periodIndex, period, setIds);
|
||||
superPeriod.isPlaceholder = true;
|
||||
return superPeriod;
|
||||
}
|
||||
};
|
||||
}
|
||||
return new PlaylistTimeline(newTimelines, uids, shuffleOrder);
|
||||
}
|
||||
|
||||
private static Object[] getUids(
|
||||
Collection<? extends MediaSourceInfoHolder> mediaSourceInfoHolders) {
|
||||
Object[] uids = new Object[mediaSourceInfoHolders.size()];
|
||||
int i = 0;
|
||||
for (MediaSourceInfoHolder holder : mediaSourceInfoHolders) {
|
||||
uids[i++] = holder.getUid();
|
||||
}
|
||||
return uids;
|
||||
}
|
||||
|
||||
private static Timeline[] getTimelines(
|
||||
Collection<? extends MediaSourceInfoHolder> mediaSourceInfoHolders) {
|
||||
Timeline[] timelines = new Timeline[mediaSourceInfoHolders.size()];
|
||||
int i = 0;
|
||||
for (MediaSourceInfoHolder holder : mediaSourceInfoHolders) {
|
||||
timelines[i++] = holder.getTimeline();
|
||||
}
|
||||
return timelines;
|
||||
}
|
||||
}
|
||||
|
@ -131,6 +131,7 @@ import androidx.media3.exoplayer.drm.DrmSessionManager;
|
||||
import androidx.media3.exoplayer.metadata.MetadataOutput;
|
||||
import androidx.media3.exoplayer.source.ClippingMediaSource;
|
||||
import androidx.media3.exoplayer.source.ConcatenatingMediaSource;
|
||||
import androidx.media3.exoplayer.source.ForwardingTimeline;
|
||||
import androidx.media3.exoplayer.source.MaskingMediaSource;
|
||||
import androidx.media3.exoplayer.source.MediaPeriod;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
@ -188,6 +189,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
@ -1629,6 +1631,7 @@ public final class ExoPlayerTest {
|
||||
.blockUntilEnded(TIMEOUT_MS);
|
||||
testRunner.assertTimelineChangeReasonsEqual(
|
||||
Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
||||
Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE,
|
||||
Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE);
|
||||
testRunner.assertPositionDiscontinuityReasonsEqual(Player.DISCONTINUITY_REASON_SEEK);
|
||||
|
||||
@ -1667,6 +1670,119 @@ public final class ExoPlayerTest {
|
||||
mediaSource.assertReleased();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stop_withLiveStream_currentPeriodIsPlaceholder() throws TimeoutException {
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
FakeTimeline fakeTimeline =
|
||||
new FakeTimeline(
|
||||
new TimelineWindowDefinition(
|
||||
/* periodCount= */ 1,
|
||||
/* id= */ 0,
|
||||
/* isSeekable= */ true,
|
||||
/* isDynamic= */ true,
|
||||
/* isLive= */ true,
|
||||
/* isPlaceholder= */ false,
|
||||
/* durationUs= */ 1000 * C.MICROS_PER_SECOND,
|
||||
/* defaultPositionUs= */ 0,
|
||||
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
|
||||
AdPlaybackState.NONE));
|
||||
player.addMediaSources(ImmutableList.of(new FakeMediaSource(fakeTimeline)));
|
||||
player.prepare();
|
||||
runUntilPlaybackState(player, Player.STATE_READY);
|
||||
assertThat(
|
||||
player
|
||||
.getCurrentTimeline()
|
||||
.getPeriod(player.getCurrentPeriodIndex(), new Timeline.Period())
|
||||
.isPlaceholder)
|
||||
.isFalse();
|
||||
|
||||
player.stop();
|
||||
|
||||
TestPlayerRunHelper.runUntilPendingCommandsAreFullyHandled(player);
|
||||
assertThat(
|
||||
player
|
||||
.getCurrentTimeline()
|
||||
.getPeriod(player.getCurrentPeriodIndex(), new Timeline.Period())
|
||||
.isPlaceholder)
|
||||
.isTrue();
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stop_withVodStream_currentPeriodIsPlaceholder() throws TimeoutException {
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
player.addMediaSources(ImmutableList.of(new FakeMediaSource()));
|
||||
player.prepare();
|
||||
runUntilPlaybackState(player, Player.STATE_READY);
|
||||
assertThat(
|
||||
player
|
||||
.getCurrentTimeline()
|
||||
.getPeriod(player.getCurrentPeriodIndex(), new Timeline.Period())
|
||||
.isPlaceholder)
|
||||
.isFalse();
|
||||
|
||||
player.stop();
|
||||
|
||||
TestPlayerRunHelper.runUntilPendingCommandsAreFullyHandled(player);
|
||||
assertThat(
|
||||
player
|
||||
.getCurrentTimeline()
|
||||
.getPeriod(player.getCurrentPeriodIndex(), new Timeline.Period())
|
||||
.isPlaceholder)
|
||||
.isTrue();
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void playbackError_withLiveStream_currentPeriodIsPlaceholder() throws TimeoutException {
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
FakeTimeline fakeTimeline =
|
||||
new FakeTimeline(
|
||||
new TimelineWindowDefinition(
|
||||
/* periodCount= */ 1,
|
||||
/* id= */ 0,
|
||||
/* isSeekable= */ true,
|
||||
/* isDynamic= */ true,
|
||||
/* isLive= */ true,
|
||||
/* isPlaceholder= */ false,
|
||||
/* durationUs= */ 1000 * C.MICROS_PER_SECOND,
|
||||
/* defaultPositionUs= */ 0,
|
||||
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
|
||||
AdPlaybackState.NONE));
|
||||
FakeMediaSource fakeMediaSource =
|
||||
new FakeMediaSource(fakeTimeline) {
|
||||
@Override
|
||||
public Timeline getInitialTimeline() {
|
||||
return fakeTimeline;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void prepareSourceInternal(
|
||||
@Nullable TransferListener mediaTransferListener) {
|
||||
super.prepareSourceInternal(mediaTransferListener);
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
};
|
||||
player.addMediaSources(ImmutableList.of(fakeMediaSource));
|
||||
player.prepare();
|
||||
assertThat(
|
||||
player
|
||||
.getCurrentTimeline()
|
||||
.getPeriod(player.getCurrentPeriodIndex(), new Timeline.Period())
|
||||
.isPlaceholder)
|
||||
.isFalse();
|
||||
|
||||
runUntilError(player);
|
||||
|
||||
assertThat(
|
||||
player
|
||||
.getCurrentTimeline()
|
||||
.getPeriod(player.getCurrentPeriodIndex(), new Timeline.Period())
|
||||
.isPlaceholder)
|
||||
.isTrue();
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void release_correctMasking() throws Exception {
|
||||
int[] currentMediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET};
|
||||
@ -2001,9 +2117,11 @@ public final class ExoPlayerTest {
|
||||
.start()
|
||||
.blockUntilActionScheduleFinished(TIMEOUT_MS)
|
||||
.blockUntilEnded(TIMEOUT_MS);
|
||||
testRunner.assertTimelinesSame(placeholderTimeline, timeline);
|
||||
testRunner.assertTimelinesSame(
|
||||
placeholderTimeline, timeline, createPlaceholderWrapperTimeline(timeline));
|
||||
testRunner.assertTimelineChangeReasonsEqual(
|
||||
Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
||||
Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE,
|
||||
Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE);
|
||||
}
|
||||
|
||||
@ -2018,7 +2136,7 @@ public final class ExoPlayerTest {
|
||||
new IOException(), PlaybackException.ERROR_CODE_IO_UNSPECIFIED))
|
||||
.waitForPlaybackState(Player.STATE_IDLE)
|
||||
.prepare()
|
||||
.waitForPlaybackState(Player.STATE_BUFFERING)
|
||||
.waitForPlaybackState(Player.STATE_READY)
|
||||
.build();
|
||||
ExoPlayerTestRunner testRunner =
|
||||
new ExoPlayerTestRunner.Builder(context)
|
||||
@ -2031,10 +2149,13 @@ public final class ExoPlayerTest {
|
||||
} catch (ExoPlaybackException e) {
|
||||
// Expected exception.
|
||||
}
|
||||
testRunner.assertTimelinesSame(placeholderTimeline, timeline);
|
||||
testRunner.assertTimelineChangeReasonsEqual(
|
||||
Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
||||
Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE,
|
||||
Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE,
|
||||
Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE);
|
||||
testRunner.assertTimelinesSame(
|
||||
placeholderTimeline, timeline, createPlaceholderWrapperTimeline(timeline), timeline);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -2068,11 +2189,28 @@ public final class ExoPlayerTest {
|
||||
long positionWhenFullyReadyAfterReprepare = player.getCurrentPosition();
|
||||
player.release();
|
||||
|
||||
// Ensure we don't receive further timeline updates when repreparing.
|
||||
verify(mockListener)
|
||||
verify(mockListener, times(4)).onTimelineChanged(any(), anyInt());
|
||||
InOrder inOrder = inOrder(mockListener);
|
||||
inOrder
|
||||
.verify(mockListener)
|
||||
.onTimelineChanged(any(), eq(Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED));
|
||||
verify(mockListener).onTimelineChanged(any(), eq(Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE));
|
||||
verify(mockListener, times(2)).onTimelineChanged(any(), anyInt());
|
||||
inOrder.verify(mockListener).onPlaybackStateChanged(Player.STATE_BUFFERING);
|
||||
// Source update at reset after playback exception (isPlaceholder=true)
|
||||
inOrder
|
||||
.verify(mockListener)
|
||||
.onTimelineChanged(any(), eq(Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE));
|
||||
inOrder.verify(mockListener).onPlaybackStateChanged(Player.STATE_READY);
|
||||
// Source update replacing wrapper timeline of reset (isPlaceholder=false)
|
||||
inOrder
|
||||
.verify(mockListener)
|
||||
.onTimelineChanged(any(), eq(Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE));
|
||||
inOrder.verify(mockListener).onPlaybackStateChanged(Player.STATE_IDLE);
|
||||
inOrder.verify(mockListener).onPlaybackStateChanged(Player.STATE_BUFFERING);
|
||||
// Source update at second preparation
|
||||
inOrder
|
||||
.verify(mockListener)
|
||||
.onTimelineChanged(any(), eq(Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE));
|
||||
inOrder.verify(mockListener).onPlaybackStateChanged(Player.STATE_READY);
|
||||
|
||||
assertThat(positionAfterSeekHandled).isEqualTo(50);
|
||||
assertThat(positionAfterReprepareHandled).isEqualTo(50);
|
||||
@ -2330,10 +2468,16 @@ public final class ExoPlayerTest {
|
||||
} catch (ExoPlaybackException e) {
|
||||
// Expected exception.
|
||||
}
|
||||
testRunner.assertTimelinesSame(placeholderTimeline, timeline, placeholderTimeline, timeline);
|
||||
testRunner.assertTimelinesSame(
|
||||
placeholderTimeline,
|
||||
timeline,
|
||||
createPlaceholderWrapperTimeline(timeline),
|
||||
placeholderTimeline,
|
||||
timeline);
|
||||
testRunner.assertTimelineChangeReasonsEqual(
|
||||
Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
||||
Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE,
|
||||
Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE,
|
||||
Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
||||
Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE);
|
||||
}
|
||||
@ -13142,4 +13286,19 @@ public final class ExoPlayerTest {
|
||||
private static ArgumentMatcher<Timeline> noUid(Timeline timeline) {
|
||||
return argument -> timelinesAreSame(argument, timeline);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a forwarding timeline that sets the {@link Timeline.Period#isPlaceholder} flag to true.
|
||||
* This is what happens when the player is stopped or a playback exception is thrown.
|
||||
*/
|
||||
private static Timeline createPlaceholderWrapperTimeline(Timeline timeline) {
|
||||
return new ForwardingTimeline(timeline) {
|
||||
@Override
|
||||
public Period getPeriod(int periodIndex, Period period, boolean setIds) {
|
||||
Period superPeriod = super.getPeriod(periodIndex, period, setIds);
|
||||
superPeriod.isPlaceholder = true;
|
||||
return superPeriod;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package androidx.media3.exoplayer;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import androidx.media3.common.Timeline;
|
||||
import androidx.media3.exoplayer.source.ShuffleOrder;
|
||||
import androidx.media3.test.utils.FakeTimeline;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.List;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/** Unit test for {@link PlaylistTimeline}. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class PlaylistTimelineTest {
|
||||
|
||||
@Test
|
||||
public void copyWithPlaceholderTimeline_equalTimelineExceptPlaceholderFlag() {
|
||||
MediaSourceInfoHolder mediaSourceInfoHolder1 = mock(MediaSourceInfoHolder.class);
|
||||
MediaSourceInfoHolder mediaSourceInfoHolder2 = mock(MediaSourceInfoHolder.class);
|
||||
ImmutableList<MediaSourceInfoHolder> mediaSourceInfoHolders =
|
||||
ImmutableList.of(mediaSourceInfoHolder1, mediaSourceInfoHolder2);
|
||||
FakeTimeline fakeTimeline1 = new FakeTimeline(2);
|
||||
FakeTimeline fakeTimeline2 = new FakeTimeline(1);
|
||||
when(mediaSourceInfoHolder1.getTimeline()).thenReturn(fakeTimeline1);
|
||||
when(mediaSourceInfoHolder1.getUid()).thenReturn("uid1");
|
||||
when(mediaSourceInfoHolder2.getTimeline()).thenReturn(fakeTimeline2);
|
||||
when(mediaSourceInfoHolder2.getUid()).thenReturn("uid2");
|
||||
ShuffleOrder.DefaultShuffleOrder shuffleOrder =
|
||||
new ShuffleOrder.DefaultShuffleOrder(mediaSourceInfoHolders.size());
|
||||
PlaylistTimeline playlistTimeline = new PlaylistTimeline(mediaSourceInfoHolders, shuffleOrder);
|
||||
|
||||
PlaylistTimeline playlistTimelineCopy =
|
||||
playlistTimeline.copyWithPlaceholderTimeline(shuffleOrder);
|
||||
|
||||
assertThat(playlistTimelineCopy).isNotEqualTo(playlistTimeline);
|
||||
assertThat(playlistTimelineCopy.getWindowCount()).isEqualTo(playlistTimeline.getWindowCount());
|
||||
assertThat(playlistTimelineCopy.getPeriodCount()).isEqualTo(playlistTimeline.getPeriodCount());
|
||||
List<Timeline> copiedChildTimelines = playlistTimelineCopy.getChildTimelines();
|
||||
List<Timeline> originalChildTimelines = playlistTimeline.getChildTimelines();
|
||||
for (int i = 0; i < copiedChildTimelines.size(); i++) {
|
||||
Timeline childTimeline = copiedChildTimelines.get(i);
|
||||
Timeline originalChildTimeline = originalChildTimelines.get(i);
|
||||
for (int j = 0; j < childTimeline.getWindowCount(); j++) {
|
||||
assertThat(childTimeline.getWindow(/* windowIndex= */ 0, new Timeline.Window()))
|
||||
.isEqualTo(
|
||||
originalChildTimeline.getWindow(/* windowIndex= */ 0, new Timeline.Window()));
|
||||
Timeline.Period expectedPeriod =
|
||||
originalChildTimeline.getPeriod(/* periodIndex= */ 0, new Timeline.Period());
|
||||
Timeline.Period actualPeriod =
|
||||
childTimeline.getPeriod(/* periodIndex= */ 0, new Timeline.Period());
|
||||
assertThat(actualPeriod).isNotEqualTo(expectedPeriod);
|
||||
actualPeriod.isPlaceholder = false;
|
||||
assertThat(actualPeriod).isEqualTo(expectedPeriod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -757,7 +757,11 @@ public final class DefaultAnalyticsCollectorTest {
|
||||
period0Seq0 /* ENDED */)
|
||||
.inOrder();
|
||||
assertThat(listener.getEvents(EVENT_TIMELINE_CHANGED))
|
||||
.containsExactly(WINDOW_0 /* prepared */, WINDOW_0 /* prepared */);
|
||||
.containsExactly(
|
||||
WINDOW_0 /* playlist change */,
|
||||
WINDOW_0 /* prepared */,
|
||||
period0Seq0 /* reset after error */,
|
||||
period0Seq0 /* second prepare */);
|
||||
assertThat(listener.getEvents(EVENT_POSITION_DISCONTINUITY)).containsExactly(period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_SEEK_STARTED)).containsExactly(period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_IS_LOADING_CHANGED))
|
||||
|
Loading…
x
Reference in New Issue
Block a user