diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java
index 1125e60690..7115ebaf5b 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java
@@ -36,6 +36,7 @@ import com.google.android.exoplayer2.source.MediaLoadData;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
+import com.google.common.base.Objects;
import java.io.IOException;
/**
@@ -155,6 +156,42 @@ public interface AnalyticsListener {
this.currentPlaybackPositionMs = currentPlaybackPositionMs;
this.totalBufferedDurationMs = totalBufferedDurationMs;
}
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ EventTime eventTime = (EventTime) o;
+ return realtimeMs == eventTime.realtimeMs
+ && windowIndex == eventTime.windowIndex
+ && eventPlaybackPositionMs == eventTime.eventPlaybackPositionMs
+ && currentWindowIndex == eventTime.currentWindowIndex
+ && currentPlaybackPositionMs == eventTime.currentPlaybackPositionMs
+ && totalBufferedDurationMs == eventTime.totalBufferedDurationMs
+ && Objects.equal(timeline, eventTime.timeline)
+ && Objects.equal(mediaPeriodId, eventTime.mediaPeriodId)
+ && Objects.equal(currentTimeline, eventTime.currentTimeline)
+ && Objects.equal(currentMediaPeriodId, eventTime.currentMediaPeriodId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(
+ realtimeMs,
+ timeline,
+ windowIndex,
+ mediaPeriodId,
+ eventPlaybackPositionMs,
+ currentTimeline,
+ currentWindowIndex,
+ currentMediaPeriodId,
+ currentPlaybackPositionMs,
+ totalBufferedDurationMs);
+ }
}
/**
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManager.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManager.java
index 04536bb6c1..b1ef52839b 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManager.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManager.java
@@ -15,6 +15,9 @@
*/
package com.google.android.exoplayer2.analytics;
+import static com.google.android.exoplayer2.C.usToMs;
+import static java.lang.Math.max;
+
import android.util.Base64;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
@@ -120,6 +123,38 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
if (currentSessionId == null) {
currentSessionId = eventSession.sessionId;
}
+ if (eventTime.mediaPeriodId != null && eventTime.mediaPeriodId.isAd()) {
+ // Ensure that the content session for an ad session is created first.
+ MediaPeriodId contentMediaPeriodId =
+ new MediaPeriodId(
+ eventTime.mediaPeriodId.periodUid,
+ eventTime.mediaPeriodId.windowSequenceNumber,
+ eventTime.mediaPeriodId.adGroupIndex);
+ SessionDescriptor contentSession =
+ getOrAddSession(eventTime.windowIndex, contentMediaPeriodId);
+ if (!contentSession.isCreated) {
+ contentSession.isCreated = true;
+ eventTime.timeline.getPeriodByUid(eventTime.mediaPeriodId.periodUid, period);
+ long adGroupPositionMs =
+ usToMs(period.getAdGroupTimeUs(eventTime.mediaPeriodId.adGroupIndex))
+ + period.getPositionInWindowMs();
+ // getAdGroupTimeUs may return 0 for prerolls despite period offset.
+ adGroupPositionMs = max(0, adGroupPositionMs);
+ EventTime eventTimeForContent =
+ new EventTime(
+ eventTime.realtimeMs,
+ eventTime.timeline,
+ eventTime.windowIndex,
+ contentMediaPeriodId,
+ /* eventPlaybackPositionMs= */ adGroupPositionMs,
+ eventTime.currentTimeline,
+ eventTime.currentWindowIndex,
+ eventTime.currentMediaPeriodId,
+ eventTime.currentPlaybackPositionMs,
+ eventTime.totalBufferedDurationMs);
+ listener.onSessionCreated(eventTimeForContent, contentSession.sessionId);
+ }
+ }
if (!eventSession.isCreated) {
eventSession.isCreated = true;
listener.onSessionCreated(eventTime, eventSession.sessionId);
@@ -131,7 +166,7 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
}
@Override
- public synchronized void handleTimelineUpdate(EventTime eventTime) {
+ public synchronized void updateSessionsWithTimelineChange(EventTime eventTime) {
Assertions.checkNotNull(listener);
Timeline previousTimeline = currentTimeline;
currentTimeline = eventTime.timeline;
@@ -149,11 +184,11 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
}
}
}
- handlePositionDiscontinuity(eventTime, Player.DISCONTINUITY_REASON_INTERNAL);
+ updateSessionsWithDiscontinuity(eventTime, Player.DISCONTINUITY_REASON_INTERNAL);
}
@Override
- public synchronized void handlePositionDiscontinuity(
+ public synchronized void updateSessionsWithDiscontinuity(
EventTime eventTime, @DiscontinuityReason int reason) {
Assertions.checkNotNull(listener);
boolean hasAutomaticTransition =
@@ -179,6 +214,7 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
SessionDescriptor currentSessionDescriptor =
getOrAddSession(eventTime.windowIndex, eventTime.mediaPeriodId);
currentSessionId = currentSessionDescriptor.sessionId;
+ updateSessions(eventTime);
if (eventTime.mediaPeriodId != null
&& eventTime.mediaPeriodId.isAd()
&& (previousSessionDescriptor == null
@@ -195,10 +231,8 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
eventTime.mediaPeriodId.periodUid, eventTime.mediaPeriodId.windowSequenceNumber);
SessionDescriptor contentSession =
getOrAddSession(eventTime.windowIndex, contentMediaPeriodId);
- if (contentSession.isCreated && currentSessionDescriptor.isCreated) {
- listener.onAdPlaybackStarted(
- eventTime, contentSession.sessionId, currentSessionDescriptor.sessionId);
- }
+ listener.onAdPlaybackStarted(
+ eventTime, contentSession.sessionId, currentSessionDescriptor.sessionId);
}
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackSessionManager.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackSessionManager.java
index 7045779125..1038f3b6e1 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackSessionManager.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackSessionManager.java
@@ -99,24 +99,34 @@ public interface PlaybackSessionManager {
/**
* Updates or creates sessions based on a player {@link EventTime}.
*
+ *
Call {@link #updateSessionsWithTimelineChange(EventTime)} or {@link
+ * #updateSessionsWithDiscontinuity(EventTime, int)} if the event is a {@link Timeline} change or
+ * a position discontinuity respectively.
+ *
* @param eventTime The {@link EventTime}.
*/
void updateSessions(EventTime eventTime);
/**
- * Updates the session associations to a new timeline.
+ * Updates or creates sessions based on a {@link Timeline} change at {@link EventTime}.
*
- * @param eventTime The event time with the timeline change.
+ *
Should be called instead of {@link #updateSessions(EventTime)} if a {@link Timeline} change
+ * occurred.
+ *
+ * @param eventTime The {@link EventTime} with the timeline change.
*/
- void handleTimelineUpdate(EventTime eventTime);
+ void updateSessionsWithTimelineChange(EventTime eventTime);
/**
- * Handles a position discontinuity.
+ * Updates or creates sessions based on a position discontinuity at {@link EventTime}.
*
- * @param eventTime The event time of the position discontinuity.
+ *
Should be called instead of {@link #updateSessions(EventTime)} if a position discontinuity
+ * occurred.
+ *
+ * @param eventTime The {@link EventTime} of the position discontinuity.
* @param reason The {@link DiscontinuityReason}.
*/
- void handlePositionDiscontinuity(EventTime eventTime, @DiscontinuityReason int reason);
+ void updateSessionsWithDiscontinuity(EventTime eventTime, @DiscontinuityReason int reason);
/**
* Finishes all existing sessions and calls their respective {@link
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java
index 662cb0b8a1..d6f8d17d31 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java
@@ -284,8 +284,7 @@ public final class PlaybackStatsListener
@Override
public void onTimelineChanged(EventTime eventTime, @Player.TimelineChangeReason int reason) {
- sessionManager.handleTimelineUpdate(eventTime);
- maybeAddSession(eventTime);
+ sessionManager.updateSessionsWithTimelineChange(eventTime);
for (String session : playbackStatsTrackers.keySet()) {
if (sessionManager.belongsToSession(eventTime, session)) {
playbackStatsTrackers.get(session).onPositionDiscontinuity(eventTime, /* isSeek= */ false);
@@ -295,8 +294,10 @@ public final class PlaybackStatsListener
@Override
public void onPositionDiscontinuity(EventTime eventTime, @Player.DiscontinuityReason int reason) {
- sessionManager.handlePositionDiscontinuity(eventTime, reason);
- maybeAddSession(eventTime);
+ boolean isCompletelyIdle = eventTime.timeline.isEmpty() && playbackState == Player.STATE_IDLE;
+ if (!isCompletelyIdle) {
+ sessionManager.updateSessionsWithDiscontinuity(eventTime, reason);
+ }
if (reason == Player.DISCONTINUITY_REASON_SEEK) {
onSeekStartedCalled = false;
}
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManagerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManagerTest.java
index a5a021c80a..08b784dee3 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManagerTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManagerTest.java
@@ -20,6 +20,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -39,6 +40,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -160,26 +162,44 @@ public final class DefaultPlaybackSessionManagerTest {
@Test
public void updateSessions_ofSameWindow_withoutMediaPeriodId_afterAd_doesNotCreateNewSession() {
- Timeline timeline = new FakeTimeline(/* windowCount= */ 1);
- MediaPeriodId mediaPeriodId =
+ Timeline timeline =
+ new FakeTimeline(
+ new TimelineWindowDefinition(
+ /* periodCount= */ 1,
+ /* id= */ new Object(),
+ /* isSeekable= */ true,
+ /* isDynamic= */ false,
+ /* durationUs= */ 10_000_000,
+ FakeTimeline.createAdPlaybackState(
+ /* adsPerGroup= */ 1, /* adGroupTimesUs... */ 0)));
+ MediaPeriodId adMediaPeriodId =
new MediaPeriodId(
timeline.getUidOfPeriod(/* periodIndex= */ 0),
/* adGroupIndex= */ 0,
/* adIndexInAdGroup= */ 0,
/* windowSequenceNumber= */ 0);
- EventTime eventTime1 = createEventTime(timeline, /* windowIndex= */ 0, mediaPeriodId);
- EventTime eventTime2 =
+ MediaPeriodId contentMediaPeriodIdDuringAd =
+ new MediaPeriodId(
+ timeline.getUidOfPeriod(/* periodIndex= */ 0),
+ /* windowSequenceNumber= */ 0,
+ /* nextAdGroupIndex= */ 0);
+ EventTime adEventTime = createEventTime(timeline, /* windowIndex= */ 0, adMediaPeriodId);
+ EventTime contentEventTimeDuringAd =
+ createEventTime(
+ timeline, /* windowIndex= */ 0, contentMediaPeriodIdDuringAd, adMediaPeriodId);
+ EventTime contentEventTimeWithoutMediaPeriodId =
createEventTime(timeline, /* windowIndex= */ 0, /* mediaPeriodId= */ null);
- sessionManager.updateSessions(eventTime1);
- sessionManager.updateSessions(eventTime2);
+ sessionManager.updateSessions(adEventTime);
+ sessionManager.updateSessions(contentEventTimeWithoutMediaPeriodId);
- ArgumentCaptor sessionId = ArgumentCaptor.forClass(String.class);
- verify(mockListener).onSessionCreated(eq(eventTime1), sessionId.capture());
- verify(mockListener).onSessionActive(eventTime1, sessionId.getValue());
+ verify(mockListener).onSessionCreated(eq(contentEventTimeDuringAd), anyString());
+ ArgumentCaptor adSessionId = ArgumentCaptor.forClass(String.class);
+ verify(mockListener).onSessionCreated(eq(adEventTime), adSessionId.capture());
+ verify(mockListener).onSessionActive(adEventTime, adSessionId.getValue());
verifyNoMoreInteractions(mockListener);
- assertThat(sessionManager.getSessionForMediaPeriodId(timeline, mediaPeriodId))
- .isEqualTo(sessionId.getValue());
+ assertThat(sessionManager.getSessionForMediaPeriodId(timeline, adMediaPeriodId))
+ .isEqualTo(adSessionId.getValue());
}
@Test
@@ -350,18 +370,6 @@ public final class DefaultPlaybackSessionManagerTest {
verifyNoMoreInteractions(mockListener);
}
- @Test
- public void getSessionForMediaPeriodId_returnsValue_butDoesNotCreateSession() {
- Timeline timeline = new FakeTimeline(/* windowCount= */ 1);
- MediaPeriodId mediaPeriodId =
- new MediaPeriodId(
- timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0);
- String session = sessionManager.getSessionForMediaPeriodId(timeline, mediaPeriodId);
-
- assertThat(session).isNotEmpty();
- verifyNoMoreInteractions(mockListener);
- }
-
@Test
public void updateSessions_afterSessionForMediaPeriodId_withSameMediaPeriodId_returnsSameValue() {
Timeline timeline = new FakeTimeline(/* windowCount= */ 1);
@@ -399,6 +407,81 @@ public final class DefaultPlaybackSessionManagerTest {
assertThat(sessionId.getValue()).isEqualTo(expectedSessionId);
}
+ @Test
+ public void
+ updateSessions_withNewAd_afterDiscontinuitiesFromContentToAdAndBack_doesNotActivateNewAd() {
+ Timeline adTimeline =
+ new FakeTimeline(
+ new TimelineWindowDefinition(
+ /* periodCount= */ 1,
+ /* id= */ 0,
+ /* isSeekable= */ true,
+ /* isDynamic= */ false,
+ /* durationUs =*/ 10 * C.MICROS_PER_SECOND,
+ new AdPlaybackState(
+ /* adGroupTimesUs=... */ 2 * C.MICROS_PER_SECOND, 5 * C.MICROS_PER_SECOND)
+ .withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
+ .withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 1)));
+ EventTime adEventTime1 =
+ createEventTime(
+ adTimeline,
+ /* windowIndex= */ 0,
+ new MediaPeriodId(
+ adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
+ /* adGroupIndex= */ 0,
+ /* adIndexInAdGroup= */ 0,
+ /* windowSequenceNumber= */ 0));
+ EventTime adEventTime2 =
+ createEventTime(
+ adTimeline,
+ /* windowIndex= */ 0,
+ new MediaPeriodId(
+ adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
+ /* adGroupIndex= */ 1,
+ /* adIndexInAdGroup= */ 0,
+ /* windowSequenceNumber= */ 0));
+ EventTime contentEventTime1 =
+ createEventTime(
+ adTimeline,
+ /* windowIndex= */ 0,
+ new MediaPeriodId(
+ adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
+ /* windowSequenceNumber= */ 0,
+ /* nextAdGroupIndex= */ 0));
+ EventTime contentEventTime2 =
+ createEventTime(
+ adTimeline,
+ /* windowIndex= */ 0,
+ new MediaPeriodId(
+ adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
+ /* windowSequenceNumber= */ 0,
+ /* nextAdGroupIndex= */ 1));
+ sessionManager.updateSessionsWithTimelineChange(contentEventTime1);
+ sessionManager.updateSessions(adEventTime1);
+ sessionManager.updateSessionsWithDiscontinuity(
+ adEventTime1, Player.DISCONTINUITY_REASON_AD_INSERTION);
+ sessionManager.updateSessionsWithDiscontinuity(
+ contentEventTime2, Player.DISCONTINUITY_REASON_AD_INSERTION);
+ String adSessionId2 =
+ sessionManager.getSessionForMediaPeriodId(adTimeline, adEventTime2.mediaPeriodId);
+
+ sessionManager.updateSessions(adEventTime2);
+
+ verify(mockListener, never()).onSessionActive(any(), eq(adSessionId2));
+ }
+
+ @Test
+ public void getSessionForMediaPeriodId_returnsValue_butDoesNotCreateSession() {
+ Timeline timeline = new FakeTimeline(/* windowCount= */ 1);
+ MediaPeriodId mediaPeriodId =
+ new MediaPeriodId(
+ timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0);
+ String session = sessionManager.getSessionForMediaPeriodId(timeline, mediaPeriodId);
+
+ assertThat(session).isNotEmpty();
+ verifyNoMoreInteractions(mockListener);
+ }
+
@Test
public void belongsToSession_withSameWindowIndex_returnsTrue() {
EventTime eventTime =
@@ -465,28 +548,38 @@ public final class DefaultPlaybackSessionManagerTest {
@Test
public void belongsToSession_withAd_returnsFalse() {
- Timeline timeline = new FakeTimeline(/* windowCount= */ 1);
- MediaPeriodId mediaPeriodId1 =
+ Timeline timeline =
+ new FakeTimeline(
+ new TimelineWindowDefinition(
+ /* periodCount= */ 1,
+ /* id= */ new Object(),
+ /* isSeekable= */ true,
+ /* isDynamic= */ false,
+ /* durationUs= */ 10_000_000,
+ FakeTimeline.createAdPlaybackState(
+ /* adsPerGroup= */ 1, /* adGroupTimesUs... */ 0)));
+ MediaPeriodId contentMediaPeriodId =
new MediaPeriodId(
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0);
- MediaPeriodId mediaPeriodId2 =
+ MediaPeriodId adMediaPeriodId =
new MediaPeriodId(
timeline.getUidOfPeriod(/* periodIndex= */ 0),
/* adGroupIndex= */ 0,
/* adIndexInAdGroup= */ 0,
/* windowSequenceNumber= */ 1);
- EventTime eventTime1 = createEventTime(timeline, /* windowIndex= */ 0, mediaPeriodId1);
- EventTime eventTime2 = createEventTime(timeline, /* windowIndex= */ 0, mediaPeriodId2);
- sessionManager.updateSessions(eventTime1);
- sessionManager.updateSessions(eventTime2);
+ EventTime contentEventTime =
+ createEventTime(timeline, /* windowIndex= */ 0, contentMediaPeriodId);
+ EventTime adEventTime = createEventTime(timeline, /* windowIndex= */ 0, adMediaPeriodId);
+ sessionManager.updateSessions(contentEventTime);
+ sessionManager.updateSessions(adEventTime);
ArgumentCaptor sessionId1 = ArgumentCaptor.forClass(String.class);
ArgumentCaptor sessionId2 = ArgumentCaptor.forClass(String.class);
- verify(mockListener).onSessionCreated(eq(eventTime1), sessionId1.capture());
- verify(mockListener).onSessionCreated(eq(eventTime2), sessionId2.capture());
- assertThat(sessionManager.belongsToSession(eventTime2, sessionId1.getValue())).isFalse();
- assertThat(sessionManager.belongsToSession(eventTime1, sessionId2.getValue())).isFalse();
- assertThat(sessionManager.belongsToSession(eventTime2, sessionId2.getValue())).isTrue();
+ verify(mockListener).onSessionCreated(eq(contentEventTime), sessionId1.capture());
+ verify(mockListener).onSessionCreated(eq(adEventTime), sessionId2.capture());
+ assertThat(sessionManager.belongsToSession(adEventTime, sessionId1.getValue())).isFalse();
+ assertThat(sessionManager.belongsToSession(contentEventTime, sessionId2.getValue())).isFalse();
+ assertThat(sessionManager.belongsToSession(adEventTime, sessionId2.getValue())).isTrue();
}
@Test
@@ -501,8 +594,7 @@ public final class DefaultPlaybackSessionManagerTest {
EventTime newTimelineEventTime =
createEventTime(timeline, /* windowIndex= */ 0, /* mediaPeriodId= */ null);
- sessionManager.handleTimelineUpdate(newTimelineEventTime);
- sessionManager.updateSessions(newTimelineEventTime);
+ sessionManager.updateSessionsWithTimelineChange(newTimelineEventTime);
ArgumentCaptor sessionId1 = ArgumentCaptor.forClass(String.class);
ArgumentCaptor sessionId2 = ArgumentCaptor.forClass(String.class);
@@ -545,8 +637,7 @@ public final class DefaultPlaybackSessionManagerTest {
new MediaPeriodId(
initialTimeline.getUidOfPeriod(/* periodIndex= */ 3),
/* windowSequenceNumber= */ 2));
- sessionManager.handleTimelineUpdate(eventForInitialTimelineId100);
- sessionManager.updateSessions(eventForInitialTimelineId100);
+ sessionManager.updateSessionsWithTimelineChange(eventForInitialTimelineId100);
sessionManager.updateSessions(eventForInitialTimelineId200);
sessionManager.updateSessions(eventForInitialTimelineId300);
String sessionId100 =
@@ -578,7 +669,7 @@ public final class DefaultPlaybackSessionManagerTest {
timelineUpdate.getUidOfPeriod(/* periodIndex= */ 0),
/* windowSequenceNumber= */ 2));
- sessionManager.handleTimelineUpdate(eventForTimelineUpdateId100);
+ sessionManager.updateSessionsWithTimelineChange(eventForTimelineUpdateId100);
String updatedSessionId100 =
sessionManager.getSessionForMediaPeriodId(
timelineUpdate, eventForTimelineUpdateId100.mediaPeriodId);
@@ -632,7 +723,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager.updateSessions(contentEventTime);
sessionManager.updateSessions(adEventTime);
- sessionManager.handleTimelineUpdate(contentEventTime);
+ sessionManager.updateSessionsWithTimelineChange(contentEventTime);
verify(mockListener, never()).onSessionFinished(any(), anyString(), anyBoolean());
}
@@ -653,13 +744,11 @@ public final class DefaultPlaybackSessionManagerTest {
/* windowIndex= */ 0,
new MediaPeriodId(
timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 0));
- sessionManager.handleTimelineUpdate(eventTime1);
- sessionManager.updateSessions(eventTime1);
+ sessionManager.updateSessionsWithTimelineChange(eventTime1);
sessionManager.updateSessions(eventTime2);
- sessionManager.handlePositionDiscontinuity(
+ sessionManager.updateSessionsWithDiscontinuity(
eventTime2, Player.DISCONTINUITY_REASON_PERIOD_TRANSITION);
- sessionManager.updateSessions(eventTime2);
verify(mockListener).onSessionCreated(eq(eventTime1), anyString());
verify(mockListener).onSessionActive(eq(eventTime1), anyString());
@@ -681,17 +770,15 @@ public final class DefaultPlaybackSessionManagerTest {
/* windowIndex= */ 1,
new MediaPeriodId(
timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 1));
- sessionManager.handleTimelineUpdate(eventTime1);
- sessionManager.updateSessions(eventTime1);
+ sessionManager.updateSessionsWithTimelineChange(eventTime1);
sessionManager.updateSessions(eventTime2);
String sessionId1 =
sessionManager.getSessionForMediaPeriodId(timeline, eventTime1.mediaPeriodId);
String sessionId2 =
sessionManager.getSessionForMediaPeriodId(timeline, eventTime2.mediaPeriodId);
- sessionManager.handlePositionDiscontinuity(
+ sessionManager.updateSessionsWithDiscontinuity(
eventTime2, Player.DISCONTINUITY_REASON_PERIOD_TRANSITION);
- sessionManager.updateSessions(eventTime2);
verify(mockListener).onSessionCreated(eventTime1, sessionId1);
verify(mockListener).onSessionActive(eventTime1, sessionId1);
@@ -717,16 +804,14 @@ public final class DefaultPlaybackSessionManagerTest {
/* windowIndex= */ 1,
new MediaPeriodId(
timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 1));
- sessionManager.handleTimelineUpdate(eventTime1);
- sessionManager.updateSessions(eventTime1);
+ sessionManager.updateSessionsWithTimelineChange(eventTime1);
sessionManager.updateSessions(eventTime2);
String sessionId1 =
sessionManager.getSessionForMediaPeriodId(timeline, eventTime1.mediaPeriodId);
String sessionId2 =
sessionManager.getSessionForMediaPeriodId(timeline, eventTime2.mediaPeriodId);
- sessionManager.handlePositionDiscontinuity(eventTime2, Player.DISCONTINUITY_REASON_SEEK);
- sessionManager.updateSessions(eventTime2);
+ sessionManager.updateSessionsWithDiscontinuity(eventTime2, Player.DISCONTINUITY_REASON_SEEK);
verify(mockListener).onSessionCreated(eventTime1, sessionId1);
verify(mockListener).onSessionActive(eventTime1, sessionId1);
@@ -748,12 +833,10 @@ public final class DefaultPlaybackSessionManagerTest {
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0));
EventTime eventTime2 =
createEventTime(timeline, /* windowIndex= */ 0, /* mediaPeriodId= */ null);
- sessionManager.handleTimelineUpdate(eventTime1);
- sessionManager.updateSessions(eventTime1);
+ sessionManager.updateSessionsWithTimelineChange(eventTime1);
sessionManager.updateSessions(eventTime2);
- sessionManager.handlePositionDiscontinuity(eventTime2, Player.DISCONTINUITY_REASON_SEEK);
- sessionManager.updateSessions(eventTime2);
+ sessionManager.updateSessionsWithDiscontinuity(eventTime2, Player.DISCONTINUITY_REASON_SEEK);
verify(mockListener, never()).onSessionFinished(any(), anyString(), anyBoolean());
}
@@ -785,7 +868,7 @@ public final class DefaultPlaybackSessionManagerTest {
/* windowIndex= */ 3,
new MediaPeriodId(
timeline.getUidOfPeriod(/* periodIndex= */ 3), /* windowSequenceNumber= */ 3));
- sessionManager.handleTimelineUpdate(eventTime1);
+ sessionManager.updateSessionsWithTimelineChange(eventTime1);
sessionManager.updateSessions(eventTime1);
sessionManager.updateSessions(eventTime2);
sessionManager.updateSessions(eventTime3);
@@ -795,8 +878,7 @@ public final class DefaultPlaybackSessionManagerTest {
String sessionId2 =
sessionManager.getSessionForMediaPeriodId(timeline, eventTime2.mediaPeriodId);
- sessionManager.handlePositionDiscontinuity(eventTime3, Player.DISCONTINUITY_REASON_SEEK);
- sessionManager.updateSessions(eventTime3);
+ sessionManager.updateSessionsWithDiscontinuity(eventTime3, Player.DISCONTINUITY_REASON_SEEK);
verify(mockListener).onSessionCreated(eventTime1, sessionId1);
verify(mockListener).onSessionActive(eventTime1, sessionId1);
@@ -842,7 +924,20 @@ public final class DefaultPlaybackSessionManagerTest {
/* adGroupIndex= */ 1,
/* adIndexInAdGroup= */ 0,
/* windowSequenceNumber= */ 0));
- EventTime contentEventTime =
+ EventTime contentEventTimeDuringPreroll =
+ createEventTime(
+ adTimeline,
+ /* windowIndex= */ 0,
+ /* eventMediaPeriodId= */ new MediaPeriodId(
+ adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
+ /* windowSequenceNumber= */ 0,
+ /* nextAdGroupIndex= */ 0),
+ /* currentMediaPeriodId= */ new MediaPeriodId(
+ adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
+ /* adGroupIndex= */ 0,
+ /* adIndexInAdGroup= */ 0,
+ /* windowSequenceNumber= */ 0));
+ EventTime contentEventTimeBetweenAds =
createEventTime(
adTimeline,
/* windowIndex= */ 0,
@@ -850,25 +945,31 @@ public final class DefaultPlaybackSessionManagerTest {
adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
/* windowSequenceNumber= */ 0,
/* nextAdGroupIndex= */ 1));
- sessionManager.handleTimelineUpdate(adEventTime1);
- sessionManager.updateSessions(adEventTime1);
+ sessionManager.updateSessionsWithTimelineChange(adEventTime1);
sessionManager.updateSessions(adEventTime2);
String adSessionId1 =
sessionManager.getSessionForMediaPeriodId(adTimeline, adEventTime1.mediaPeriodId);
+ String contentSessionId =
+ sessionManager.getSessionForMediaPeriodId(
+ adTimeline, contentEventTimeDuringPreroll.mediaPeriodId);
- sessionManager.handlePositionDiscontinuity(
- contentEventTime, Player.DISCONTINUITY_REASON_AD_INSERTION);
- sessionManager.updateSessions(contentEventTime);
+ sessionManager.updateSessionsWithDiscontinuity(
+ contentEventTimeBetweenAds, Player.DISCONTINUITY_REASON_AD_INSERTION);
- verify(mockListener).onSessionCreated(adEventTime1, adSessionId1);
- verify(mockListener).onSessionActive(adEventTime1, adSessionId1);
- verify(mockListener).onSessionCreated(eq(adEventTime2), anyString());
- verify(mockListener)
+ InOrder inOrder = inOrder(mockListener);
+ inOrder.verify(mockListener).onSessionCreated(contentEventTimeDuringPreroll, contentSessionId);
+ inOrder.verify(mockListener).onSessionCreated(adEventTime1, adSessionId1);
+ inOrder.verify(mockListener).onSessionActive(adEventTime1, adSessionId1);
+ inOrder.verify(mockListener).onAdPlaybackStarted(adEventTime1, contentSessionId, adSessionId1);
+ inOrder.verify(mockListener).onSessionCreated(eq(adEventTime2), anyString());
+ inOrder
+ .verify(mockListener)
.onSessionFinished(
- contentEventTime, adSessionId1, /* automaticTransitionToNextPlayback= */ true);
- verify(mockListener).onSessionCreated(eq(contentEventTime), anyString());
- verify(mockListener).onSessionActive(eq(contentEventTime), anyString());
- verifyNoMoreInteractions(mockListener);
+ contentEventTimeBetweenAds,
+ adSessionId1,
+ /* automaticTransitionToNextPlayback= */ true);
+ inOrder.verify(mockListener).onSessionActive(eq(contentEventTimeBetweenAds), anyString());
+ inOrder.verifyNoMoreInteractions();
}
@Test
@@ -911,14 +1012,12 @@ public final class DefaultPlaybackSessionManagerTest {
adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
/* windowSequenceNumber= */ 0,
/* nextAdGroupIndex= */ 0));
- sessionManager.handleTimelineUpdate(contentEventTime);
- sessionManager.updateSessions(contentEventTime);
+ sessionManager.updateSessionsWithTimelineChange(contentEventTime);
sessionManager.updateSessions(adEventTime1);
sessionManager.updateSessions(adEventTime2);
- sessionManager.handlePositionDiscontinuity(
+ sessionManager.updateSessionsWithDiscontinuity(
adEventTime1, Player.DISCONTINUITY_REASON_AD_INSERTION);
- sessionManager.updateSessions(adEventTime1);
verify(mockListener, never()).onSessionFinished(any(), anyString(), anyBoolean());
}
@@ -962,8 +1061,7 @@ public final class DefaultPlaybackSessionManagerTest {
adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
/* windowSequenceNumber= */ 0,
/* nextAdGroupIndex= */ 1));
- sessionManager.handleTimelineUpdate(contentEventTime);
- sessionManager.updateSessions(contentEventTime);
+ sessionManager.updateSessionsWithTimelineChange(contentEventTime);
sessionManager.updateSessions(adEventTime1);
sessionManager.updateSessions(adEventTime2);
String contentSessionId =
@@ -973,11 +1071,9 @@ public final class DefaultPlaybackSessionManagerTest {
String adSessionId2 =
sessionManager.getSessionForMediaPeriodId(adTimeline, adEventTime2.mediaPeriodId);
- sessionManager.handlePositionDiscontinuity(
+ sessionManager.updateSessionsWithDiscontinuity(
adEventTime1, Player.DISCONTINUITY_REASON_AD_INSERTION);
- sessionManager.updateSessions(adEventTime1);
- sessionManager.handlePositionDiscontinuity(adEventTime2, Player.DISCONTINUITY_REASON_SEEK);
- sessionManager.updateSessions(adEventTime2);
+ sessionManager.updateSessionsWithDiscontinuity(adEventTime2, Player.DISCONTINUITY_REASON_SEEK);
verify(mockListener).onSessionCreated(eq(contentEventTime), anyString());
verify(mockListener).onSessionActive(eq(contentEventTime), anyString());
@@ -993,72 +1089,6 @@ public final class DefaultPlaybackSessionManagerTest {
verifyNoMoreInteractions(mockListener);
}
- @Test
- public void
- updateSessions_withNewAd_afterDiscontinuitiesFromContentToAdAndBack_doesNotActivateNewAd() {
- Timeline adTimeline =
- new FakeTimeline(
- new TimelineWindowDefinition(
- /* periodCount= */ 1,
- /* id= */ 0,
- /* isSeekable= */ true,
- /* isDynamic= */ false,
- /* durationUs =*/ 10 * C.MICROS_PER_SECOND,
- new AdPlaybackState(
- /* adGroupTimesUs=... */ 2 * C.MICROS_PER_SECOND, 5 * C.MICROS_PER_SECOND)
- .withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
- .withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 1)));
- EventTime adEventTime1 =
- createEventTime(
- adTimeline,
- /* windowIndex= */ 0,
- new MediaPeriodId(
- adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
- /* adGroupIndex= */ 0,
- /* adIndexInAdGroup= */ 0,
- /* windowSequenceNumber= */ 0));
- EventTime adEventTime2 =
- createEventTime(
- adTimeline,
- /* windowIndex= */ 0,
- new MediaPeriodId(
- adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
- /* adGroupIndex= */ 1,
- /* adIndexInAdGroup= */ 0,
- /* windowSequenceNumber= */ 0));
- EventTime contentEventTime1 =
- createEventTime(
- adTimeline,
- /* windowIndex= */ 0,
- new MediaPeriodId(
- adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
- /* windowSequenceNumber= */ 0,
- /* nextAdGroupIndex= */ 0));
- EventTime contentEventTime2 =
- createEventTime(
- adTimeline,
- /* windowIndex= */ 0,
- new MediaPeriodId(
- adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
- /* windowSequenceNumber= */ 0,
- /* nextAdGroupIndex= */ 1));
- sessionManager.handleTimelineUpdate(contentEventTime1);
- sessionManager.updateSessions(contentEventTime1);
- sessionManager.updateSessions(adEventTime1);
- sessionManager.handlePositionDiscontinuity(
- adEventTime1, Player.DISCONTINUITY_REASON_AD_INSERTION);
- sessionManager.updateSessions(adEventTime1);
- sessionManager.handlePositionDiscontinuity(
- contentEventTime2, Player.DISCONTINUITY_REASON_AD_INSERTION);
- sessionManager.updateSessions(contentEventTime2);
- String adSessionId2 =
- sessionManager.getSessionForMediaPeriodId(adTimeline, adEventTime2.mediaPeriodId);
-
- sessionManager.updateSessions(adEventTime2);
-
- verify(mockListener, never()).onSessionActive(any(), eq(adSessionId2));
- }
-
@Test
public void finishAllSessions_callsOnSessionFinishedForAllCreatedSessions() {
Timeline timeline = new FakeTimeline(/* windowCount= */ 4);
@@ -1098,4 +1128,22 @@ public final class DefaultPlaybackSessionManagerTest {
/* currentPlaybackPositionMs= */ 0,
/* totalBufferedDurationMs= */ 0);
}
+
+ private static EventTime createEventTime(
+ Timeline timeline,
+ int windowIndex,
+ @Nullable MediaPeriodId eventMediaPeriodId,
+ @Nullable MediaPeriodId currentMediaPeriodId) {
+ return new EventTime(
+ /* realtimeMs = */ 0,
+ timeline,
+ windowIndex,
+ eventMediaPeriodId,
+ /* eventPlaybackPositionMs= */ 0,
+ timeline,
+ windowIndex,
+ currentMediaPeriodId,
+ /* currentPlaybackPositionMs= */ 0,
+ /* totalBufferedDurationMs= */ 0);
+ }
}