Commit bb787d66 by tonihei Committed by Oliver Woodman

Ensure onAdPlaybackStarted is only called after the session is created

We currently try to call onAdPlaybackStarted even if the ad session
is not created yet and if not, we never call the callback afterwards.

Make sure to update and create the current session before trying to
send onAdPlaybackStarted.

As a result, we can merge updateSessions into the existing
handleTimelineChanged and handleDiscontinuity calls as they always
need to be called together.

PiperOrigin-RevId: 321383860
parent 8cc3cc4e
...@@ -36,6 +36,7 @@ import com.google.android.exoplayer2.source.MediaLoadData; ...@@ -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.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.common.base.Objects;
import java.io.IOException; import java.io.IOException;
/** /**
...@@ -155,6 +156,42 @@ public interface AnalyticsListener { ...@@ -155,6 +156,42 @@ public interface AnalyticsListener {
this.currentPlaybackPositionMs = currentPlaybackPositionMs; this.currentPlaybackPositionMs = currentPlaybackPositionMs;
this.totalBufferedDurationMs = totalBufferedDurationMs; 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);
}
} }
/** /**
......
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
*/ */
package com.google.android.exoplayer2.analytics; 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 android.util.Base64;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
...@@ -120,6 +123,38 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag ...@@ -120,6 +123,38 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
if (currentSessionId == null) { if (currentSessionId == null) {
currentSessionId = eventSession.sessionId; 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) { if (!eventSession.isCreated) {
eventSession.isCreated = true; eventSession.isCreated = true;
listener.onSessionCreated(eventTime, eventSession.sessionId); listener.onSessionCreated(eventTime, eventSession.sessionId);
...@@ -131,7 +166,7 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag ...@@ -131,7 +166,7 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
} }
@Override @Override
public synchronized void handleTimelineUpdate(EventTime eventTime) { public synchronized void updateSessionsWithTimelineChange(EventTime eventTime) {
Assertions.checkNotNull(listener); Assertions.checkNotNull(listener);
Timeline previousTimeline = currentTimeline; Timeline previousTimeline = currentTimeline;
currentTimeline = eventTime.timeline; currentTimeline = eventTime.timeline;
...@@ -149,11 +184,11 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag ...@@ -149,11 +184,11 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
} }
} }
} }
handlePositionDiscontinuity(eventTime, Player.DISCONTINUITY_REASON_INTERNAL); updateSessionsWithDiscontinuity(eventTime, Player.DISCONTINUITY_REASON_INTERNAL);
} }
@Override @Override
public synchronized void handlePositionDiscontinuity( public synchronized void updateSessionsWithDiscontinuity(
EventTime eventTime, @DiscontinuityReason int reason) { EventTime eventTime, @DiscontinuityReason int reason) {
Assertions.checkNotNull(listener); Assertions.checkNotNull(listener);
boolean hasAutomaticTransition = boolean hasAutomaticTransition =
...@@ -179,6 +214,7 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag ...@@ -179,6 +214,7 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
SessionDescriptor currentSessionDescriptor = SessionDescriptor currentSessionDescriptor =
getOrAddSession(eventTime.windowIndex, eventTime.mediaPeriodId); getOrAddSession(eventTime.windowIndex, eventTime.mediaPeriodId);
currentSessionId = currentSessionDescriptor.sessionId; currentSessionId = currentSessionDescriptor.sessionId;
updateSessions(eventTime);
if (eventTime.mediaPeriodId != null if (eventTime.mediaPeriodId != null
&& eventTime.mediaPeriodId.isAd() && eventTime.mediaPeriodId.isAd()
&& (previousSessionDescriptor == null && (previousSessionDescriptor == null
...@@ -195,12 +231,10 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag ...@@ -195,12 +231,10 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
eventTime.mediaPeriodId.periodUid, eventTime.mediaPeriodId.windowSequenceNumber); eventTime.mediaPeriodId.periodUid, eventTime.mediaPeriodId.windowSequenceNumber);
SessionDescriptor contentSession = SessionDescriptor contentSession =
getOrAddSession(eventTime.windowIndex, contentMediaPeriodId); getOrAddSession(eventTime.windowIndex, contentMediaPeriodId);
if (contentSession.isCreated && currentSessionDescriptor.isCreated) {
listener.onAdPlaybackStarted( listener.onAdPlaybackStarted(
eventTime, contentSession.sessionId, currentSessionDescriptor.sessionId); eventTime, contentSession.sessionId, currentSessionDescriptor.sessionId);
} }
} }
}
@Override @Override
public void finishAllSessions(EventTime eventTime) { public void finishAllSessions(EventTime eventTime) {
......
...@@ -99,24 +99,34 @@ public interface PlaybackSessionManager { ...@@ -99,24 +99,34 @@ public interface PlaybackSessionManager {
/** /**
* Updates or creates sessions based on a player {@link EventTime}. * Updates or creates sessions based on a player {@link EventTime}.
* *
* <p>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}. * @param eventTime The {@link EventTime}.
*/ */
void updateSessions(EventTime 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}.
*
* <p>Should be called instead of {@link #updateSessions(EventTime)} if a {@link Timeline} change
* occurred.
* *
* @param eventTime The event time with the timeline change. * @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}.
*
* <p>Should be called instead of {@link #updateSessions(EventTime)} if a position discontinuity
* occurred.
* *
* @param eventTime The event time of the position discontinuity. * @param eventTime The {@link EventTime} of the position discontinuity.
* @param reason The {@link DiscontinuityReason}. * @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 * Finishes all existing sessions and calls their respective {@link
......
...@@ -284,8 +284,7 @@ public final class PlaybackStatsListener ...@@ -284,8 +284,7 @@ public final class PlaybackStatsListener
@Override @Override
public void onTimelineChanged(EventTime eventTime, @Player.TimelineChangeReason int reason) { public void onTimelineChanged(EventTime eventTime, @Player.TimelineChangeReason int reason) {
sessionManager.handleTimelineUpdate(eventTime); sessionManager.updateSessionsWithTimelineChange(eventTime);
maybeAddSession(eventTime);
for (String session : playbackStatsTrackers.keySet()) { for (String session : playbackStatsTrackers.keySet()) {
if (sessionManager.belongsToSession(eventTime, session)) { if (sessionManager.belongsToSession(eventTime, session)) {
playbackStatsTrackers.get(session).onPositionDiscontinuity(eventTime, /* isSeek= */ false); playbackStatsTrackers.get(session).onPositionDiscontinuity(eventTime, /* isSeek= */ false);
...@@ -295,8 +294,10 @@ public final class PlaybackStatsListener ...@@ -295,8 +294,10 @@ public final class PlaybackStatsListener
@Override @Override
public void onPositionDiscontinuity(EventTime eventTime, @Player.DiscontinuityReason int reason) { public void onPositionDiscontinuity(EventTime eventTime, @Player.DiscontinuityReason int reason) {
sessionManager.handlePositionDiscontinuity(eventTime, reason); boolean isCompletelyIdle = eventTime.timeline.isEmpty() && playbackState == Player.STATE_IDLE;
maybeAddSession(eventTime); if (!isCompletelyIdle) {
sessionManager.updateSessionsWithDiscontinuity(eventTime, reason);
}
if (reason == Player.DISCONTINUITY_REASON_SEEK) { if (reason == Player.DISCONTINUITY_REASON_SEEK) {
onSeekStartedCalled = false; onSeekStartedCalled = false;
} }
......
...@@ -20,6 +20,7 @@ import static org.mockito.ArgumentMatchers.any; ...@@ -20,6 +20,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
...@@ -39,6 +40,7 @@ import org.junit.Before; ...@@ -39,6 +40,7 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
...@@ -160,26 +162,44 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -160,26 +162,44 @@ public final class DefaultPlaybackSessionManagerTest {
@Test @Test
public void updateSessions_ofSameWindow_withoutMediaPeriodId_afterAd_doesNotCreateNewSession() { public void updateSessions_ofSameWindow_withoutMediaPeriodId_afterAd_doesNotCreateNewSession() {
Timeline timeline = new FakeTimeline(/* windowCount= */ 1); Timeline timeline =
MediaPeriodId mediaPeriodId = 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( new MediaPeriodId(
timeline.getUidOfPeriod(/* periodIndex= */ 0), timeline.getUidOfPeriod(/* periodIndex= */ 0),
/* adGroupIndex= */ 0, /* adGroupIndex= */ 0,
/* adIndexInAdGroup= */ 0, /* adIndexInAdGroup= */ 0,
/* windowSequenceNumber= */ 0); /* windowSequenceNumber= */ 0);
EventTime eventTime1 = createEventTime(timeline, /* windowIndex= */ 0, mediaPeriodId); MediaPeriodId contentMediaPeriodIdDuringAd =
EventTime eventTime2 = 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); createEventTime(timeline, /* windowIndex= */ 0, /* mediaPeriodId= */ null);
sessionManager.updateSessions(eventTime1); sessionManager.updateSessions(adEventTime);
sessionManager.updateSessions(eventTime2); sessionManager.updateSessions(contentEventTimeWithoutMediaPeriodId);
ArgumentCaptor<String> sessionId = ArgumentCaptor.forClass(String.class); verify(mockListener).onSessionCreated(eq(contentEventTimeDuringAd), anyString());
verify(mockListener).onSessionCreated(eq(eventTime1), sessionId.capture()); ArgumentCaptor<String> adSessionId = ArgumentCaptor.forClass(String.class);
verify(mockListener).onSessionActive(eventTime1, sessionId.getValue()); verify(mockListener).onSessionCreated(eq(adEventTime), adSessionId.capture());
verify(mockListener).onSessionActive(adEventTime, adSessionId.getValue());
verifyNoMoreInteractions(mockListener); verifyNoMoreInteractions(mockListener);
assertThat(sessionManager.getSessionForMediaPeriodId(timeline, mediaPeriodId)) assertThat(sessionManager.getSessionForMediaPeriodId(timeline, adMediaPeriodId))
.isEqualTo(sessionId.getValue()); .isEqualTo(adSessionId.getValue());
} }
@Test @Test
...@@ -351,18 +371,6 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -351,18 +371,6 @@ public final class DefaultPlaybackSessionManagerTest {
} }
@Test @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() { public void updateSessions_afterSessionForMediaPeriodId_withSameMediaPeriodId_returnsSameValue() {
Timeline timeline = new FakeTimeline(/* windowCount= */ 1); Timeline timeline = new FakeTimeline(/* windowCount= */ 1);
MediaPeriodId mediaPeriodId = MediaPeriodId mediaPeriodId =
...@@ -400,6 +408,81 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -400,6 +408,81 @@ public final class DefaultPlaybackSessionManagerTest {
} }
@Test @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() { public void belongsToSession_withSameWindowIndex_returnsTrue() {
EventTime eventTime = EventTime eventTime =
createEventTime(Timeline.EMPTY, /* windowIndex= */ 0, /* mediaPeriodId= */ null); createEventTime(Timeline.EMPTY, /* windowIndex= */ 0, /* mediaPeriodId= */ null);
...@@ -465,28 +548,38 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -465,28 +548,38 @@ public final class DefaultPlaybackSessionManagerTest {
@Test @Test
public void belongsToSession_withAd_returnsFalse() { public void belongsToSession_withAd_returnsFalse() {
Timeline timeline = new FakeTimeline(/* windowCount= */ 1); Timeline timeline =
MediaPeriodId mediaPeriodId1 = 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( new MediaPeriodId(
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0); timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0);
MediaPeriodId mediaPeriodId2 = MediaPeriodId adMediaPeriodId =
new MediaPeriodId( new MediaPeriodId(
timeline.getUidOfPeriod(/* periodIndex= */ 0), timeline.getUidOfPeriod(/* periodIndex= */ 0),
/* adGroupIndex= */ 0, /* adGroupIndex= */ 0,
/* adIndexInAdGroup= */ 0, /* adIndexInAdGroup= */ 0,
/* windowSequenceNumber= */ 1); /* windowSequenceNumber= */ 1);
EventTime eventTime1 = createEventTime(timeline, /* windowIndex= */ 0, mediaPeriodId1); EventTime contentEventTime =
EventTime eventTime2 = createEventTime(timeline, /* windowIndex= */ 0, mediaPeriodId2); createEventTime(timeline, /* windowIndex= */ 0, contentMediaPeriodId);
sessionManager.updateSessions(eventTime1); EventTime adEventTime = createEventTime(timeline, /* windowIndex= */ 0, adMediaPeriodId);
sessionManager.updateSessions(eventTime2); sessionManager.updateSessions(contentEventTime);
sessionManager.updateSessions(adEventTime);
ArgumentCaptor<String> sessionId1 = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> sessionId1 = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<String> sessionId2 = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> sessionId2 = ArgumentCaptor.forClass(String.class);
verify(mockListener).onSessionCreated(eq(eventTime1), sessionId1.capture()); verify(mockListener).onSessionCreated(eq(contentEventTime), sessionId1.capture());
verify(mockListener).onSessionCreated(eq(eventTime2), sessionId2.capture()); verify(mockListener).onSessionCreated(eq(adEventTime), sessionId2.capture());
assertThat(sessionManager.belongsToSession(eventTime2, sessionId1.getValue())).isFalse(); assertThat(sessionManager.belongsToSession(adEventTime, sessionId1.getValue())).isFalse();
assertThat(sessionManager.belongsToSession(eventTime1, sessionId2.getValue())).isFalse(); assertThat(sessionManager.belongsToSession(contentEventTime, sessionId2.getValue())).isFalse();
assertThat(sessionManager.belongsToSession(eventTime2, sessionId2.getValue())).isTrue(); assertThat(sessionManager.belongsToSession(adEventTime, sessionId2.getValue())).isTrue();
} }
@Test @Test
...@@ -501,8 +594,7 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -501,8 +594,7 @@ public final class DefaultPlaybackSessionManagerTest {
EventTime newTimelineEventTime = EventTime newTimelineEventTime =
createEventTime(timeline, /* windowIndex= */ 0, /* mediaPeriodId= */ null); createEventTime(timeline, /* windowIndex= */ 0, /* mediaPeriodId= */ null);
sessionManager.handleTimelineUpdate(newTimelineEventTime); sessionManager.updateSessionsWithTimelineChange(newTimelineEventTime);
sessionManager.updateSessions(newTimelineEventTime);
ArgumentCaptor<String> sessionId1 = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> sessionId1 = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<String> sessionId2 = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> sessionId2 = ArgumentCaptor.forClass(String.class);
...@@ -545,8 +637,7 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -545,8 +637,7 @@ public final class DefaultPlaybackSessionManagerTest {
new MediaPeriodId( new MediaPeriodId(
initialTimeline.getUidOfPeriod(/* periodIndex= */ 3), initialTimeline.getUidOfPeriod(/* periodIndex= */ 3),
/* windowSequenceNumber= */ 2)); /* windowSequenceNumber= */ 2));
sessionManager.handleTimelineUpdate(eventForInitialTimelineId100); sessionManager.updateSessionsWithTimelineChange(eventForInitialTimelineId100);
sessionManager.updateSessions(eventForInitialTimelineId100);
sessionManager.updateSessions(eventForInitialTimelineId200); sessionManager.updateSessions(eventForInitialTimelineId200);
sessionManager.updateSessions(eventForInitialTimelineId300); sessionManager.updateSessions(eventForInitialTimelineId300);
String sessionId100 = String sessionId100 =
...@@ -578,7 +669,7 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -578,7 +669,7 @@ public final class DefaultPlaybackSessionManagerTest {
timelineUpdate.getUidOfPeriod(/* periodIndex= */ 0), timelineUpdate.getUidOfPeriod(/* periodIndex= */ 0),
/* windowSequenceNumber= */ 2)); /* windowSequenceNumber= */ 2));
sessionManager.handleTimelineUpdate(eventForTimelineUpdateId100); sessionManager.updateSessionsWithTimelineChange(eventForTimelineUpdateId100);
String updatedSessionId100 = String updatedSessionId100 =
sessionManager.getSessionForMediaPeriodId( sessionManager.getSessionForMediaPeriodId(
timelineUpdate, eventForTimelineUpdateId100.mediaPeriodId); timelineUpdate, eventForTimelineUpdateId100.mediaPeriodId);
...@@ -632,7 +723,7 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -632,7 +723,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager.updateSessions(contentEventTime); sessionManager.updateSessions(contentEventTime);
sessionManager.updateSessions(adEventTime); sessionManager.updateSessions(adEventTime);
sessionManager.handleTimelineUpdate(contentEventTime); sessionManager.updateSessionsWithTimelineChange(contentEventTime);
verify(mockListener, never()).onSessionFinished(any(), anyString(), anyBoolean()); verify(mockListener, never()).onSessionFinished(any(), anyString(), anyBoolean());
} }
...@@ -653,13 +744,11 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -653,13 +744,11 @@ public final class DefaultPlaybackSessionManagerTest {
/* windowIndex= */ 0, /* windowIndex= */ 0,
new MediaPeriodId( new MediaPeriodId(
timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 0)); timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 0));
sessionManager.handleTimelineUpdate(eventTime1); sessionManager.updateSessionsWithTimelineChange(eventTime1);
sessionManager.updateSessions(eventTime1);
sessionManager.updateSessions(eventTime2); sessionManager.updateSessions(eventTime2);
sessionManager.handlePositionDiscontinuity( sessionManager.updateSessionsWithDiscontinuity(
eventTime2, Player.DISCONTINUITY_REASON_PERIOD_TRANSITION); eventTime2, Player.DISCONTINUITY_REASON_PERIOD_TRANSITION);
sessionManager.updateSessions(eventTime2);
verify(mockListener).onSessionCreated(eq(eventTime1), anyString()); verify(mockListener).onSessionCreated(eq(eventTime1), anyString());
verify(mockListener).onSessionActive(eq(eventTime1), anyString()); verify(mockListener).onSessionActive(eq(eventTime1), anyString());
...@@ -681,17 +770,15 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -681,17 +770,15 @@ public final class DefaultPlaybackSessionManagerTest {
/* windowIndex= */ 1, /* windowIndex= */ 1,
new MediaPeriodId( new MediaPeriodId(
timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 1)); timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 1));
sessionManager.handleTimelineUpdate(eventTime1); sessionManager.updateSessionsWithTimelineChange(eventTime1);
sessionManager.updateSessions(eventTime1);
sessionManager.updateSessions(eventTime2); sessionManager.updateSessions(eventTime2);
String sessionId1 = String sessionId1 =
sessionManager.getSessionForMediaPeriodId(timeline, eventTime1.mediaPeriodId); sessionManager.getSessionForMediaPeriodId(timeline, eventTime1.mediaPeriodId);
String sessionId2 = String sessionId2 =
sessionManager.getSessionForMediaPeriodId(timeline, eventTime2.mediaPeriodId); sessionManager.getSessionForMediaPeriodId(timeline, eventTime2.mediaPeriodId);
sessionManager.handlePositionDiscontinuity( sessionManager.updateSessionsWithDiscontinuity(
eventTime2, Player.DISCONTINUITY_REASON_PERIOD_TRANSITION); eventTime2, Player.DISCONTINUITY_REASON_PERIOD_TRANSITION);
sessionManager.updateSessions(eventTime2);
verify(mockListener).onSessionCreated(eventTime1, sessionId1); verify(mockListener).onSessionCreated(eventTime1, sessionId1);
verify(mockListener).onSessionActive(eventTime1, sessionId1); verify(mockListener).onSessionActive(eventTime1, sessionId1);
...@@ -717,16 +804,14 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -717,16 +804,14 @@ public final class DefaultPlaybackSessionManagerTest {
/* windowIndex= */ 1, /* windowIndex= */ 1,
new MediaPeriodId( new MediaPeriodId(
timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 1)); timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 1));
sessionManager.handleTimelineUpdate(eventTime1); sessionManager.updateSessionsWithTimelineChange(eventTime1);
sessionManager.updateSessions(eventTime1);
sessionManager.updateSessions(eventTime2); sessionManager.updateSessions(eventTime2);
String sessionId1 = String sessionId1 =
sessionManager.getSessionForMediaPeriodId(timeline, eventTime1.mediaPeriodId); sessionManager.getSessionForMediaPeriodId(timeline, eventTime1.mediaPeriodId);
String sessionId2 = String sessionId2 =
sessionManager.getSessionForMediaPeriodId(timeline, eventTime2.mediaPeriodId); sessionManager.getSessionForMediaPeriodId(timeline, eventTime2.mediaPeriodId);
sessionManager.handlePositionDiscontinuity(eventTime2, Player.DISCONTINUITY_REASON_SEEK); sessionManager.updateSessionsWithDiscontinuity(eventTime2, Player.DISCONTINUITY_REASON_SEEK);
sessionManager.updateSessions(eventTime2);
verify(mockListener).onSessionCreated(eventTime1, sessionId1); verify(mockListener).onSessionCreated(eventTime1, sessionId1);
verify(mockListener).onSessionActive(eventTime1, sessionId1); verify(mockListener).onSessionActive(eventTime1, sessionId1);
...@@ -748,12 +833,10 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -748,12 +833,10 @@ public final class DefaultPlaybackSessionManagerTest {
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0)); timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0));
EventTime eventTime2 = EventTime eventTime2 =
createEventTime(timeline, /* windowIndex= */ 0, /* mediaPeriodId= */ null); createEventTime(timeline, /* windowIndex= */ 0, /* mediaPeriodId= */ null);
sessionManager.handleTimelineUpdate(eventTime1); sessionManager.updateSessionsWithTimelineChange(eventTime1);
sessionManager.updateSessions(eventTime1);
sessionManager.updateSessions(eventTime2); sessionManager.updateSessions(eventTime2);
sessionManager.handlePositionDiscontinuity(eventTime2, Player.DISCONTINUITY_REASON_SEEK); sessionManager.updateSessionsWithDiscontinuity(eventTime2, Player.DISCONTINUITY_REASON_SEEK);
sessionManager.updateSessions(eventTime2);
verify(mockListener, never()).onSessionFinished(any(), anyString(), anyBoolean()); verify(mockListener, never()).onSessionFinished(any(), anyString(), anyBoolean());
} }
...@@ -785,7 +868,7 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -785,7 +868,7 @@ public final class DefaultPlaybackSessionManagerTest {
/* windowIndex= */ 3, /* windowIndex= */ 3,
new MediaPeriodId( new MediaPeriodId(
timeline.getUidOfPeriod(/* periodIndex= */ 3), /* windowSequenceNumber= */ 3)); timeline.getUidOfPeriod(/* periodIndex= */ 3), /* windowSequenceNumber= */ 3));
sessionManager.handleTimelineUpdate(eventTime1); sessionManager.updateSessionsWithTimelineChange(eventTime1);
sessionManager.updateSessions(eventTime1); sessionManager.updateSessions(eventTime1);
sessionManager.updateSessions(eventTime2); sessionManager.updateSessions(eventTime2);
sessionManager.updateSessions(eventTime3); sessionManager.updateSessions(eventTime3);
...@@ -795,8 +878,7 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -795,8 +878,7 @@ public final class DefaultPlaybackSessionManagerTest {
String sessionId2 = String sessionId2 =
sessionManager.getSessionForMediaPeriodId(timeline, eventTime2.mediaPeriodId); sessionManager.getSessionForMediaPeriodId(timeline, eventTime2.mediaPeriodId);
sessionManager.handlePositionDiscontinuity(eventTime3, Player.DISCONTINUITY_REASON_SEEK); sessionManager.updateSessionsWithDiscontinuity(eventTime3, Player.DISCONTINUITY_REASON_SEEK);
sessionManager.updateSessions(eventTime3);
verify(mockListener).onSessionCreated(eventTime1, sessionId1); verify(mockListener).onSessionCreated(eventTime1, sessionId1);
verify(mockListener).onSessionActive(eventTime1, sessionId1); verify(mockListener).onSessionActive(eventTime1, sessionId1);
...@@ -842,7 +924,20 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -842,7 +924,20 @@ public final class DefaultPlaybackSessionManagerTest {
/* adGroupIndex= */ 1, /* adGroupIndex= */ 1,
/* adIndexInAdGroup= */ 0, /* adIndexInAdGroup= */ 0,
/* windowSequenceNumber= */ 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( createEventTime(
adTimeline, adTimeline,
/* windowIndex= */ 0, /* windowIndex= */ 0,
...@@ -850,25 +945,31 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -850,25 +945,31 @@ public final class DefaultPlaybackSessionManagerTest {
adTimeline.getUidOfPeriod(/* periodIndex= */ 0), adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
/* windowSequenceNumber= */ 0, /* windowSequenceNumber= */ 0,
/* nextAdGroupIndex= */ 1)); /* nextAdGroupIndex= */ 1));
sessionManager.handleTimelineUpdate(adEventTime1); sessionManager.updateSessionsWithTimelineChange(adEventTime1);
sessionManager.updateSessions(adEventTime1);
sessionManager.updateSessions(adEventTime2); sessionManager.updateSessions(adEventTime2);
String adSessionId1 = String adSessionId1 =
sessionManager.getSessionForMediaPeriodId(adTimeline, adEventTime1.mediaPeriodId); sessionManager.getSessionForMediaPeriodId(adTimeline, adEventTime1.mediaPeriodId);
String contentSessionId =
sessionManager.handlePositionDiscontinuity( sessionManager.getSessionForMediaPeriodId(
contentEventTime, Player.DISCONTINUITY_REASON_AD_INSERTION); adTimeline, contentEventTimeDuringPreroll.mediaPeriodId);
sessionManager.updateSessions(contentEventTime);
sessionManager.updateSessionsWithDiscontinuity(
verify(mockListener).onSessionCreated(adEventTime1, adSessionId1); contentEventTimeBetweenAds, Player.DISCONTINUITY_REASON_AD_INSERTION);
verify(mockListener).onSessionActive(adEventTime1, adSessionId1);
verify(mockListener).onSessionCreated(eq(adEventTime2), anyString()); InOrder inOrder = inOrder(mockListener);
verify(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( .onSessionFinished(
contentEventTime, adSessionId1, /* automaticTransitionToNextPlayback= */ true); contentEventTimeBetweenAds,
verify(mockListener).onSessionCreated(eq(contentEventTime), anyString()); adSessionId1,
verify(mockListener).onSessionActive(eq(contentEventTime), anyString()); /* automaticTransitionToNextPlayback= */ true);
verifyNoMoreInteractions(mockListener); inOrder.verify(mockListener).onSessionActive(eq(contentEventTimeBetweenAds), anyString());
inOrder.verifyNoMoreInteractions();
} }
@Test @Test
...@@ -911,14 +1012,12 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -911,14 +1012,12 @@ public final class DefaultPlaybackSessionManagerTest {
adTimeline.getUidOfPeriod(/* periodIndex= */ 0), adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
/* windowSequenceNumber= */ 0, /* windowSequenceNumber= */ 0,
/* nextAdGroupIndex= */ 0)); /* nextAdGroupIndex= */ 0));
sessionManager.handleTimelineUpdate(contentEventTime); sessionManager.updateSessionsWithTimelineChange(contentEventTime);
sessionManager.updateSessions(contentEventTime);
sessionManager.updateSessions(adEventTime1); sessionManager.updateSessions(adEventTime1);
sessionManager.updateSessions(adEventTime2); sessionManager.updateSessions(adEventTime2);
sessionManager.handlePositionDiscontinuity( sessionManager.updateSessionsWithDiscontinuity(
adEventTime1, Player.DISCONTINUITY_REASON_AD_INSERTION); adEventTime1, Player.DISCONTINUITY_REASON_AD_INSERTION);
sessionManager.updateSessions(adEventTime1);
verify(mockListener, never()).onSessionFinished(any(), anyString(), anyBoolean()); verify(mockListener, never()).onSessionFinished(any(), anyString(), anyBoolean());
} }
...@@ -962,8 +1061,7 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -962,8 +1061,7 @@ public final class DefaultPlaybackSessionManagerTest {
adTimeline.getUidOfPeriod(/* periodIndex= */ 0), adTimeline.getUidOfPeriod(/* periodIndex= */ 0),
/* windowSequenceNumber= */ 0, /* windowSequenceNumber= */ 0,
/* nextAdGroupIndex= */ 1)); /* nextAdGroupIndex= */ 1));
sessionManager.handleTimelineUpdate(contentEventTime); sessionManager.updateSessionsWithTimelineChange(contentEventTime);
sessionManager.updateSessions(contentEventTime);
sessionManager.updateSessions(adEventTime1); sessionManager.updateSessions(adEventTime1);
sessionManager.updateSessions(adEventTime2); sessionManager.updateSessions(adEventTime2);
String contentSessionId = String contentSessionId =
...@@ -973,11 +1071,9 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -973,11 +1071,9 @@ public final class DefaultPlaybackSessionManagerTest {
String adSessionId2 = String adSessionId2 =
sessionManager.getSessionForMediaPeriodId(adTimeline, adEventTime2.mediaPeriodId); sessionManager.getSessionForMediaPeriodId(adTimeline, adEventTime2.mediaPeriodId);
sessionManager.handlePositionDiscontinuity( sessionManager.updateSessionsWithDiscontinuity(
adEventTime1, Player.DISCONTINUITY_REASON_AD_INSERTION); adEventTime1, Player.DISCONTINUITY_REASON_AD_INSERTION);
sessionManager.updateSessions(adEventTime1); sessionManager.updateSessionsWithDiscontinuity(adEventTime2, Player.DISCONTINUITY_REASON_SEEK);
sessionManager.handlePositionDiscontinuity(adEventTime2, Player.DISCONTINUITY_REASON_SEEK);
sessionManager.updateSessions(adEventTime2);
verify(mockListener).onSessionCreated(eq(contentEventTime), anyString()); verify(mockListener).onSessionCreated(eq(contentEventTime), anyString());
verify(mockListener).onSessionActive(eq(contentEventTime), anyString()); verify(mockListener).onSessionActive(eq(contentEventTime), anyString());
...@@ -994,72 +1090,6 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -994,72 +1090,6 @@ public final class DefaultPlaybackSessionManagerTest {
} }
@Test @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() { public void finishAllSessions_callsOnSessionFinishedForAllCreatedSessions() {
Timeline timeline = new FakeTimeline(/* windowCount= */ 4); Timeline timeline = new FakeTimeline(/* windowCount= */ 4);
EventTime eventTimeWindow0 = EventTime eventTimeWindow0 =
...@@ -1098,4 +1128,22 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -1098,4 +1128,22 @@ public final class DefaultPlaybackSessionManagerTest {
/* currentPlaybackPositionMs= */ 0, /* currentPlaybackPositionMs= */ 0,
/* totalBufferedDurationMs= */ 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);
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment