End finished sessions on timeline updates.

We currently only end sessions on Timeline updates if the associated media
is no longer in the playlist. But we should also end all sessions that are
finished as a result of the timeline update (similar to how this is done for
discontinuities). This issue was introduced by 394ab7bcfd

PiperOrigin-RevId: 423075855
This commit is contained in:
tonihei 2022-01-20 16:36:54 +00:00 committed by Ian Baker
parent 6fd4401e87
commit 7c60e67f84
2 changed files with 124 additions and 1 deletions

View file

@ -177,7 +177,8 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
Iterator<SessionDescriptor> iterator = sessions.values().iterator();
while (iterator.hasNext()) {
SessionDescriptor session = iterator.next();
if (!session.tryResolvingToNewTimeline(previousTimeline, currentTimeline)) {
if (!session.tryResolvingToNewTimeline(previousTimeline, currentTimeline)
|| session.isFinishedAtEventTime(eventTime)) {
iterator.remove();
if (session.isCreated) {
if (session.sessionId.equals(currentSessionId)) {

View file

@ -743,6 +743,128 @@ public final class DefaultPlaybackSessionManagerTest {
verify(mockListener, never()).onSessionFinished(any(), anyString(), anyBoolean());
}
@Test
public void timelineUpdate_toNewMediaWithWindowIndexOnly_finishesOtherSessions() {
Timeline firstTimeline =
new FakeTimeline(
new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 1000),
new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 2000),
new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 3000));
EventTime eventTimeFirstTimelineWithPeriodId =
createEventTime(
firstTimeline,
/* windowIndex= */ 0,
new MediaPeriodId(
firstTimeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0));
EventTime eventTimeFirstTimelineWindowOnly1 =
createEventTime(firstTimeline, /* windowIndex= */ 1, /* mediaPeriodId= */ null);
EventTime eventTimeFirstTimelineWindowOnly2 =
createEventTime(firstTimeline, /* windowIndex= */ 2, /* mediaPeriodId= */ null);
Timeline secondTimeline =
new FakeTimeline(
new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 2000),
new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 4000));
EventTime eventTimeSecondTimeline =
createEventTime(secondTimeline, /* windowIndex= */ 0, /* mediaPeriodId= */ null);
sessionManager.updateSessionsWithTimelineChange(eventTimeFirstTimelineWithPeriodId);
sessionManager.updateSessions(eventTimeFirstTimelineWindowOnly1);
sessionManager.updateSessions(eventTimeFirstTimelineWindowOnly2);
sessionManager.updateSessionsWithTimelineChange(eventTimeSecondTimeline);
InOrder inOrder = inOrder(mockListener);
ArgumentCaptor<String> firstId = ArgumentCaptor.forClass(String.class);
inOrder
.verify(mockListener)
.onSessionCreated(eq(eventTimeFirstTimelineWithPeriodId), firstId.capture());
inOrder
.verify(mockListener)
.onSessionActive(eventTimeFirstTimelineWithPeriodId, firstId.getValue());
ArgumentCaptor<String> secondId = ArgumentCaptor.forClass(String.class);
inOrder
.verify(mockListener)
.onSessionCreated(eq(eventTimeFirstTimelineWindowOnly1), secondId.capture());
ArgumentCaptor<String> thirdId = ArgumentCaptor.forClass(String.class);
inOrder
.verify(mockListener)
.onSessionCreated(eq(eventTimeFirstTimelineWindowOnly2), thirdId.capture());
inOrder
.verify(mockListener)
.onSessionFinished(
eventTimeSecondTimeline,
firstId.getValue(),
/* automaticTransitionToNextPlayback= */ false);
inOrder
.verify(mockListener)
.onSessionFinished(
eventTimeSecondTimeline,
thirdId.getValue(),
/* automaticTransitionToNextPlayback= */ false);
inOrder.verify(mockListener).onSessionActive(eventTimeSecondTimeline, secondId.getValue());
inOrder.verifyNoMoreInteractions();
}
@Test
public void timelineUpdate_toNewMediaWithMediaPeriodId_finishesOtherSessions() {
Timeline firstTimeline =
new FakeTimeline(
new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 1000),
new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 2000),
new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 3000));
EventTime eventTimeFirstTimeline1 =
createEventTime(
firstTimeline,
/* windowIndex= */ 0,
new MediaPeriodId(
firstTimeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0));
EventTime eventTimeFirstTimeline2 =
createEventTime(
firstTimeline,
/* windowIndex= */ 1,
new MediaPeriodId(
firstTimeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 1));
EventTime eventTimeFirstTimeline3 =
createEventTime(
firstTimeline,
/* windowIndex= */ 2,
new MediaPeriodId(
firstTimeline.getUidOfPeriod(/* periodIndex= */ 2), /* windowSequenceNumber= */ 2));
Timeline secondTimeline =
new FakeTimeline(
new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 2000),
new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 1000),
new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 3000));
EventTime eventTimeSecondTimeline =
createEventTime(
secondTimeline,
/* windowIndex= */ 0,
new MediaPeriodId(
secondTimeline.getUidOfPeriod(/* periodIndex= */ 0),
/* windowSequenceNumber= */ 1));
sessionManager.updateSessionsWithTimelineChange(eventTimeFirstTimeline1);
sessionManager.updateSessions(eventTimeFirstTimeline2);
sessionManager.updateSessions(eventTimeFirstTimeline3);
sessionManager.updateSessionsWithTimelineChange(eventTimeSecondTimeline);
InOrder inOrder = inOrder(mockListener);
ArgumentCaptor<String> firstId = ArgumentCaptor.forClass(String.class);
inOrder.verify(mockListener).onSessionCreated(eq(eventTimeFirstTimeline1), firstId.capture());
inOrder.verify(mockListener).onSessionActive(eventTimeFirstTimeline1, firstId.getValue());
ArgumentCaptor<String> secondId = ArgumentCaptor.forClass(String.class);
inOrder.verify(mockListener).onSessionCreated(eq(eventTimeFirstTimeline2), secondId.capture());
ArgumentCaptor<String> thirdId = ArgumentCaptor.forClass(String.class);
inOrder.verify(mockListener).onSessionCreated(eq(eventTimeFirstTimeline3), thirdId.capture());
inOrder
.verify(mockListener)
.onSessionFinished(
eventTimeSecondTimeline,
firstId.getValue(),
/* automaticTransitionToNextPlayback= */ false);
inOrder.verify(mockListener).onSessionActive(eventTimeSecondTimeline, secondId.getValue());
inOrder.verifyNoMoreInteractions();
}
@Test
public void positionDiscontinuity_withinWindow_doesNotFinishSession() {
Timeline timeline =