未验证 提交 9830c773 编写于 作者: O Oliver Woodman 提交者: GitHub

Merge pull request #7455 from google/dev-v2-r2.11.5-7193

Merge fix for #7193 into dev-v2-r2.11.5
...@@ -29,7 +29,6 @@ import java.util.HashMap; ...@@ -29,7 +29,6 @@ import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Random; import java.util.Random;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** /**
* Default {@link PlaybackSessionManager} which instantiates a new session for each window in the * Default {@link PlaybackSessionManager} which instantiates a new session for each window in the
...@@ -48,8 +47,7 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag ...@@ -48,8 +47,7 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
private @MonotonicNonNull Listener listener; private @MonotonicNonNull Listener listener;
private Timeline currentTimeline; private Timeline currentTimeline;
@Nullable private MediaPeriodId currentMediaPeriodId; @Nullable private String currentSessionId;
@Nullable private String activeSessionId;
/** Creates session manager. */ /** Creates session manager. */
public DefaultPlaybackSessionManager() { public DefaultPlaybackSessionManager() {
...@@ -83,22 +81,34 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag ...@@ -83,22 +81,34 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
@Override @Override
public synchronized void updateSessions(EventTime eventTime) { public synchronized void updateSessions(EventTime eventTime) {
boolean isObviouslyFinished = Assertions.checkNotNull(listener);
eventTime.mediaPeriodId != null @Nullable SessionDescriptor currentSession = sessions.get(currentSessionId);
&& currentMediaPeriodId != null if (eventTime.mediaPeriodId != null && currentSession != null) {
&& eventTime.mediaPeriodId.windowSequenceNumber // If we receive an event associated with a media period, then it needs to be either part of
< currentMediaPeriodId.windowSequenceNumber; // the current window if it's the first created media period, or a window that will be played
if (!isObviouslyFinished) { // in the future. Otherwise, we know that it belongs to a session that was already finished
SessionDescriptor descriptor = // and we can ignore the event.
getOrAddSession(eventTime.windowIndex, eventTime.mediaPeriodId); boolean isAlreadyFinished =
if (!descriptor.isCreated) { currentSession.windowSequenceNumber == C.INDEX_UNSET
descriptor.isCreated = true; ? currentSession.windowIndex != eventTime.windowIndex
Assertions.checkNotNull(listener).onSessionCreated(eventTime, descriptor.sessionId); : eventTime.mediaPeriodId.windowSequenceNumber < currentSession.windowSequenceNumber;
if (activeSessionId == null) { if (isAlreadyFinished) {
updateActiveSession(eventTime, descriptor); return;
}
} }
} }
SessionDescriptor eventSession =
getOrAddSession(eventTime.windowIndex, eventTime.mediaPeriodId);
if (currentSessionId == null) {
currentSessionId = eventSession.sessionId;
}
if (!eventSession.isCreated) {
eventSession.isCreated = true;
listener.onSessionCreated(eventTime, eventSession.sessionId);
}
if (eventSession.sessionId.equals(currentSessionId) && !eventSession.isActive) {
eventSession.isActive = true;
listener.onSessionActive(eventTime, eventSession.sessionId);
}
} }
@Override @Override
...@@ -112,8 +122,8 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag ...@@ -112,8 +122,8 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
if (!session.tryResolvingToNewTimeline(previousTimeline, currentTimeline)) { if (!session.tryResolvingToNewTimeline(previousTimeline, currentTimeline)) {
iterator.remove(); iterator.remove();
if (session.isCreated) { if (session.isCreated) {
if (session.sessionId.equals(activeSessionId)) { if (session.sessionId.equals(currentSessionId)) {
activeSessionId = null; currentSessionId = null;
} }
listener.onSessionFinished( listener.onSessionFinished(
eventTime, session.sessionId, /* automaticTransitionToNextPlayback= */ false); eventTime, session.sessionId, /* automaticTransitionToNextPlayback= */ false);
...@@ -136,36 +146,55 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag ...@@ -136,36 +146,55 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
if (session.isFinishedAtEventTime(eventTime)) { if (session.isFinishedAtEventTime(eventTime)) {
iterator.remove(); iterator.remove();
if (session.isCreated) { if (session.isCreated) {
boolean isRemovingActiveSession = session.sessionId.equals(activeSessionId); boolean isRemovingCurrentSession = session.sessionId.equals(currentSessionId);
boolean isAutomaticTransition = hasAutomaticTransition && isRemovingActiveSession; boolean isAutomaticTransition =
if (isRemovingActiveSession) { hasAutomaticTransition && isRemovingCurrentSession && session.isActive;
activeSessionId = null; if (isRemovingCurrentSession) {
currentSessionId = null;
} }
listener.onSessionFinished(eventTime, session.sessionId, isAutomaticTransition); listener.onSessionFinished(eventTime, session.sessionId, isAutomaticTransition);
} }
} }
} }
SessionDescriptor activeSessionDescriptor = @Nullable SessionDescriptor previousSessionDescriptor = sessions.get(currentSessionId);
SessionDescriptor currentSessionDescriptor =
getOrAddSession(eventTime.windowIndex, eventTime.mediaPeriodId); getOrAddSession(eventTime.windowIndex, eventTime.mediaPeriodId);
currentSessionId = currentSessionDescriptor.sessionId;
if (eventTime.mediaPeriodId != null if (eventTime.mediaPeriodId != null
&& eventTime.mediaPeriodId.isAd() && eventTime.mediaPeriodId.isAd()
&& (currentMediaPeriodId == null && (previousSessionDescriptor == null
|| currentMediaPeriodId.windowSequenceNumber || previousSessionDescriptor.windowSequenceNumber
!= eventTime.mediaPeriodId.windowSequenceNumber != eventTime.mediaPeriodId.windowSequenceNumber
|| currentMediaPeriodId.adGroupIndex != eventTime.mediaPeriodId.adGroupIndex || previousSessionDescriptor.adMediaPeriodId == null
|| currentMediaPeriodId.adIndexInAdGroup != eventTime.mediaPeriodId.adIndexInAdGroup)) { || previousSessionDescriptor.adMediaPeriodId.adGroupIndex
!= eventTime.mediaPeriodId.adGroupIndex
|| previousSessionDescriptor.adMediaPeriodId.adIndexInAdGroup
!= eventTime.mediaPeriodId.adIndexInAdGroup)) {
// New ad playback started. Find corresponding content session and notify ad playback started. // New ad playback started. Find corresponding content session and notify ad playback started.
MediaPeriodId contentMediaPeriodId = MediaPeriodId contentMediaPeriodId =
new MediaPeriodId( new MediaPeriodId(
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 && activeSessionDescriptor.isCreated) { if (contentSession.isCreated && currentSessionDescriptor.isCreated) {
listener.onAdPlaybackStarted( listener.onAdPlaybackStarted(
eventTime, contentSession.sessionId, activeSessionDescriptor.sessionId); eventTime, contentSession.sessionId, currentSessionDescriptor.sessionId);
}
}
}
@Override
public void finishAllSessions(EventTime eventTime) {
currentSessionId = null;
Iterator<SessionDescriptor> iterator = sessions.values().iterator();
while (iterator.hasNext()) {
SessionDescriptor session = iterator.next();
iterator.remove();
if (session.isCreated && listener != null) {
listener.onSessionFinished(
eventTime, session.sessionId, /* automaticTransitionToNextPlayback= */ false);
} }
} }
updateActiveSession(eventTime, activeSessionDescriptor);
} }
private SessionDescriptor getOrAddSession( private SessionDescriptor getOrAddSession(
...@@ -199,18 +228,6 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag ...@@ -199,18 +228,6 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
return bestMatch; return bestMatch;
} }
@RequiresNonNull("listener")
private void updateActiveSession(EventTime eventTime, SessionDescriptor sessionDescriptor) {
currentMediaPeriodId = eventTime.mediaPeriodId;
if (sessionDescriptor.isCreated) {
activeSessionId = sessionDescriptor.sessionId;
if (!sessionDescriptor.isActive) {
sessionDescriptor.isActive = true;
listener.onSessionActive(eventTime, sessionDescriptor.sessionId);
}
}
}
private static String generateSessionId() { private static String generateSessionId() {
byte[] randomBytes = new byte[SESSION_ID_LENGTH]; byte[] randomBytes = new byte[SESSION_ID_LENGTH];
RANDOM.nextBytes(randomBytes); RANDOM.nextBytes(randomBytes);
...@@ -284,8 +301,7 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag ...@@ -284,8 +301,7 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
int eventWindowIndex, @Nullable MediaPeriodId eventMediaPeriodId) { int eventWindowIndex, @Nullable MediaPeriodId eventMediaPeriodId) {
if (windowSequenceNumber == C.INDEX_UNSET if (windowSequenceNumber == C.INDEX_UNSET
&& eventWindowIndex == windowIndex && eventWindowIndex == windowIndex
&& eventMediaPeriodId != null && eventMediaPeriodId != null) {
&& !eventMediaPeriodId.isAd()) {
// Set window sequence number for this session as soon as we have one. // Set window sequence number for this session as soon as we have one.
windowSequenceNumber = eventMediaPeriodId.windowSequenceNumber; windowSequenceNumber = eventMediaPeriodId.windowSequenceNumber;
} }
......
...@@ -117,4 +117,12 @@ public interface PlaybackSessionManager { ...@@ -117,4 +117,12 @@ public interface PlaybackSessionManager {
* @param reason The {@link DiscontinuityReason}. * @param reason The {@link DiscontinuityReason}.
*/ */
void handlePositionDiscontinuity(EventTime eventTime, @DiscontinuityReason int reason); void handlePositionDiscontinuity(EventTime eventTime, @DiscontinuityReason int reason);
/**
* Finishes all existing sessions and calls their respective {@link
* Listener#onSessionFinished(EventTime, String, boolean)} callback.
*
* @param eventTime The event time at which sessions are finished.
*/
void finishAllSessions(EventTime eventTime);
} }
...@@ -148,7 +148,6 @@ public final class PlaybackStatsListener ...@@ -148,7 +148,6 @@ public final class PlaybackStatsListener
// TODO: Add AnalyticsListener.onAttachedToPlayer and onDetachedFromPlayer to auto-release with // TODO: Add AnalyticsListener.onAttachedToPlayer and onDetachedFromPlayer to auto-release with
// an actual EventTime. Should also simplify other cases where the listener needs to be released // an actual EventTime. Should also simplify other cases where the listener needs to be released
// separately from the player. // separately from the player.
HashMap<String, PlaybackStatsTracker> trackerCopy = new HashMap<>(playbackStatsTrackers);
EventTime dummyEventTime = EventTime dummyEventTime =
new EventTime( new EventTime(
SystemClock.elapsedRealtime(), SystemClock.elapsedRealtime(),
...@@ -158,9 +157,7 @@ public final class PlaybackStatsListener ...@@ -158,9 +157,7 @@ public final class PlaybackStatsListener
/* eventPlaybackPositionMs= */ 0, /* eventPlaybackPositionMs= */ 0,
/* currentPlaybackPositionMs= */ 0, /* currentPlaybackPositionMs= */ 0,
/* totalBufferedDurationMs= */ 0); /* totalBufferedDurationMs= */ 0);
for (String session : trackerCopy.keySet()) { sessionManager.finishAllSessions(dummyEventTime);
onSessionFinished(dummyEventTime, session, /* automaticTransition= */ false);
}
} }
// PlaybackSessionManager.Listener implementation. // PlaybackSessionManager.Listener implementation.
...@@ -243,7 +240,7 @@ public final class PlaybackStatsListener ...@@ -243,7 +240,7 @@ public final class PlaybackStatsListener
EventTime eventTime, boolean playWhenReady, @Player.State int playbackState) { EventTime eventTime, boolean playWhenReady, @Player.State int playbackState) {
this.playWhenReady = playWhenReady; this.playWhenReady = playWhenReady;
this.playbackState = playbackState; this.playbackState = playbackState;
sessionManager.updateSessions(eventTime); maybeAddSession(eventTime);
for (String session : playbackStatsTrackers.keySet()) { for (String session : playbackStatsTrackers.keySet()) {
boolean belongsToPlayback = sessionManager.belongsToSession(eventTime, session); boolean belongsToPlayback = sessionManager.belongsToSession(eventTime, session);
playbackStatsTrackers playbackStatsTrackers
...@@ -256,7 +253,7 @@ public final class PlaybackStatsListener ...@@ -256,7 +253,7 @@ public final class PlaybackStatsListener
public void onPlaybackSuppressionReasonChanged( public void onPlaybackSuppressionReasonChanged(
EventTime eventTime, int playbackSuppressionReason) { EventTime eventTime, int playbackSuppressionReason) {
isSuppressed = playbackSuppressionReason != Player.PLAYBACK_SUPPRESSION_REASON_NONE; isSuppressed = playbackSuppressionReason != Player.PLAYBACK_SUPPRESSION_REASON_NONE;
sessionManager.updateSessions(eventTime); maybeAddSession(eventTime);
for (String session : playbackStatsTrackers.keySet()) { for (String session : playbackStatsTrackers.keySet()) {
boolean belongsToPlayback = sessionManager.belongsToSession(eventTime, session); boolean belongsToPlayback = sessionManager.belongsToSession(eventTime, session);
playbackStatsTrackers playbackStatsTrackers
...@@ -268,7 +265,7 @@ public final class PlaybackStatsListener ...@@ -268,7 +265,7 @@ public final class PlaybackStatsListener
@Override @Override
public void onTimelineChanged(EventTime eventTime, int reason) { public void onTimelineChanged(EventTime eventTime, int reason) {
sessionManager.handleTimelineUpdate(eventTime); sessionManager.handleTimelineUpdate(eventTime);
sessionManager.updateSessions(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); playbackStatsTrackers.get(session).onPositionDiscontinuity(eventTime);
...@@ -279,7 +276,7 @@ public final class PlaybackStatsListener ...@@ -279,7 +276,7 @@ public final class PlaybackStatsListener
@Override @Override
public void onPositionDiscontinuity(EventTime eventTime, int reason) { public void onPositionDiscontinuity(EventTime eventTime, int reason) {
sessionManager.handlePositionDiscontinuity(eventTime, reason); sessionManager.handlePositionDiscontinuity(eventTime, reason);
sessionManager.updateSessions(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); playbackStatsTrackers.get(session).onPositionDiscontinuity(eventTime);
...@@ -289,7 +286,7 @@ public final class PlaybackStatsListener ...@@ -289,7 +286,7 @@ public final class PlaybackStatsListener
@Override @Override
public void onSeekStarted(EventTime eventTime) { public void onSeekStarted(EventTime eventTime) {
sessionManager.updateSessions(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).onSeekStarted(eventTime); playbackStatsTrackers.get(session).onSeekStarted(eventTime);
...@@ -299,7 +296,7 @@ public final class PlaybackStatsListener ...@@ -299,7 +296,7 @@ public final class PlaybackStatsListener
@Override @Override
public void onSeekProcessed(EventTime eventTime) { public void onSeekProcessed(EventTime eventTime) {
sessionManager.updateSessions(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).onSeekProcessed(eventTime); playbackStatsTrackers.get(session).onSeekProcessed(eventTime);
...@@ -309,7 +306,7 @@ public final class PlaybackStatsListener ...@@ -309,7 +306,7 @@ public final class PlaybackStatsListener
@Override @Override
public void onPlayerError(EventTime eventTime, ExoPlaybackException error) { public void onPlayerError(EventTime eventTime, ExoPlaybackException error) {
sessionManager.updateSessions(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).onFatalError(eventTime, error); playbackStatsTrackers.get(session).onFatalError(eventTime, error);
...@@ -321,7 +318,7 @@ public final class PlaybackStatsListener ...@@ -321,7 +318,7 @@ public final class PlaybackStatsListener
public void onPlaybackParametersChanged( public void onPlaybackParametersChanged(
EventTime eventTime, PlaybackParameters playbackParameters) { EventTime eventTime, PlaybackParameters playbackParameters) {
playbackSpeed = playbackParameters.speed; playbackSpeed = playbackParameters.speed;
sessionManager.updateSessions(eventTime); maybeAddSession(eventTime);
for (PlaybackStatsTracker tracker : playbackStatsTrackers.values()) { for (PlaybackStatsTracker tracker : playbackStatsTrackers.values()) {
tracker.onPlaybackSpeedChanged(eventTime, playbackSpeed); tracker.onPlaybackSpeedChanged(eventTime, playbackSpeed);
} }
...@@ -330,7 +327,7 @@ public final class PlaybackStatsListener ...@@ -330,7 +327,7 @@ public final class PlaybackStatsListener
@Override @Override
public void onTracksChanged( public void onTracksChanged(
EventTime eventTime, TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { EventTime eventTime, TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
sessionManager.updateSessions(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).onTracksChanged(eventTime, trackSelections); playbackStatsTrackers.get(session).onTracksChanged(eventTime, trackSelections);
...@@ -341,7 +338,7 @@ public final class PlaybackStatsListener ...@@ -341,7 +338,7 @@ public final class PlaybackStatsListener
@Override @Override
public void onLoadStarted( public void onLoadStarted(
EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) { EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
sessionManager.updateSessions(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).onLoadStarted(eventTime); playbackStatsTrackers.get(session).onLoadStarted(eventTime);
...@@ -351,7 +348,7 @@ public final class PlaybackStatsListener ...@@ -351,7 +348,7 @@ public final class PlaybackStatsListener
@Override @Override
public void onDownstreamFormatChanged(EventTime eventTime, MediaLoadData mediaLoadData) { public void onDownstreamFormatChanged(EventTime eventTime, MediaLoadData mediaLoadData) {
sessionManager.updateSessions(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).onDownstreamFormatChanged(eventTime, mediaLoadData); playbackStatsTrackers.get(session).onDownstreamFormatChanged(eventTime, mediaLoadData);
...@@ -366,7 +363,7 @@ public final class PlaybackStatsListener ...@@ -366,7 +363,7 @@ public final class PlaybackStatsListener
int height, int height,
int unappliedRotationDegrees, int unappliedRotationDegrees,
float pixelWidthHeightRatio) { float pixelWidthHeightRatio) {
sessionManager.updateSessions(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).onVideoSizeChanged(eventTime, width, height); playbackStatsTrackers.get(session).onVideoSizeChanged(eventTime, width, height);
...@@ -377,7 +374,7 @@ public final class PlaybackStatsListener ...@@ -377,7 +374,7 @@ public final class PlaybackStatsListener
@Override @Override
public void onBandwidthEstimate( public void onBandwidthEstimate(
EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate) { EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate) {
sessionManager.updateSessions(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).onBandwidthData(totalLoadTimeMs, totalBytesLoaded); playbackStatsTrackers.get(session).onBandwidthData(totalLoadTimeMs, totalBytesLoaded);
...@@ -388,7 +385,7 @@ public final class PlaybackStatsListener ...@@ -388,7 +385,7 @@ public final class PlaybackStatsListener
@Override @Override
public void onAudioUnderrun( public void onAudioUnderrun(
EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) { EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {
sessionManager.updateSessions(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).onAudioUnderrun(); playbackStatsTrackers.get(session).onAudioUnderrun();
...@@ -398,7 +395,7 @@ public final class PlaybackStatsListener ...@@ -398,7 +395,7 @@ public final class PlaybackStatsListener
@Override @Override
public void onDroppedVideoFrames(EventTime eventTime, int droppedFrames, long elapsedMs) { public void onDroppedVideoFrames(EventTime eventTime, int droppedFrames, long elapsedMs) {
sessionManager.updateSessions(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).onDroppedVideoFrames(droppedFrames); playbackStatsTrackers.get(session).onDroppedVideoFrames(droppedFrames);
...@@ -413,7 +410,7 @@ public final class PlaybackStatsListener ...@@ -413,7 +410,7 @@ public final class PlaybackStatsListener
MediaLoadData mediaLoadData, MediaLoadData mediaLoadData,
IOException error, IOException error,
boolean wasCanceled) { boolean wasCanceled) {
sessionManager.updateSessions(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).onNonFatalError(eventTime, error); playbackStatsTrackers.get(session).onNonFatalError(eventTime, error);
...@@ -423,7 +420,7 @@ public final class PlaybackStatsListener ...@@ -423,7 +420,7 @@ public final class PlaybackStatsListener
@Override @Override
public void onDrmSessionManagerError(EventTime eventTime, Exception error) { public void onDrmSessionManagerError(EventTime eventTime, Exception error) {
sessionManager.updateSessions(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).onNonFatalError(eventTime, error); playbackStatsTrackers.get(session).onNonFatalError(eventTime, error);
...@@ -431,6 +428,13 @@ public final class PlaybackStatsListener ...@@ -431,6 +428,13 @@ public final class PlaybackStatsListener
} }
} }
private void maybeAddSession(EventTime eventTime) {
boolean isCompletelyIdle = eventTime.timeline.isEmpty() && playbackState == Player.STATE_IDLE;
if (!isCompletelyIdle) {
sessionManager.updateSessions(eventTime);
}
}
/** Tracker for playback stats of a single playback. */ /** Tracker for playback stats of a single playback. */
private static final class PlaybackStatsTracker { private static final class PlaybackStatsTracker {
......
...@@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean; ...@@ -21,6 +21,7 @@ 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.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
...@@ -501,6 +502,7 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -501,6 +502,7 @@ public final class DefaultPlaybackSessionManagerTest {
createEventTime(timeline, /* windowIndex= */ 0, /* mediaPeriodId= */ null); createEventTime(timeline, /* windowIndex= */ 0, /* mediaPeriodId= */ null);
sessionManager.handleTimelineUpdate(newTimelineEventTime); sessionManager.handleTimelineUpdate(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);
...@@ -657,6 +659,7 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -657,6 +659,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager.handlePositionDiscontinuity( sessionManager.handlePositionDiscontinuity(
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());
...@@ -688,6 +691,7 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -688,6 +691,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager.handlePositionDiscontinuity( sessionManager.handlePositionDiscontinuity(
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);
...@@ -722,6 +726,7 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -722,6 +726,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager.getSessionForMediaPeriodId(timeline, eventTime2.mediaPeriodId); sessionManager.getSessionForMediaPeriodId(timeline, eventTime2.mediaPeriodId);
sessionManager.handlePositionDiscontinuity(eventTime2, Player.DISCONTINUITY_REASON_SEEK); sessionManager.handlePositionDiscontinuity(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,6 +753,7 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -748,6 +753,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager.updateSessions(eventTime2); sessionManager.updateSessions(eventTime2);
sessionManager.handlePositionDiscontinuity(eventTime2, Player.DISCONTINUITY_REASON_SEEK); sessionManager.handlePositionDiscontinuity(eventTime2, Player.DISCONTINUITY_REASON_SEEK);
sessionManager.updateSessions(eventTime2);
verify(mockListener, never()).onSessionFinished(any(), anyString(), anyBoolean()); verify(mockListener, never()).onSessionFinished(any(), anyString(), anyBoolean());
} }
...@@ -790,6 +796,7 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -790,6 +796,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager.getSessionForMediaPeriodId(timeline, eventTime2.mediaPeriodId); sessionManager.getSessionForMediaPeriodId(timeline, eventTime2.mediaPeriodId);
sessionManager.handlePositionDiscontinuity(eventTime3, Player.DISCONTINUITY_REASON_SEEK); sessionManager.handlePositionDiscontinuity(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);
...@@ -851,6 +858,7 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -851,6 +858,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager.handlePositionDiscontinuity( sessionManager.handlePositionDiscontinuity(
contentEventTime, Player.DISCONTINUITY_REASON_AD_INSERTION); contentEventTime, Player.DISCONTINUITY_REASON_AD_INSERTION);
sessionManager.updateSessions(contentEventTime);
verify(mockListener).onSessionCreated(adEventTime1, adSessionId1); verify(mockListener).onSessionCreated(adEventTime1, adSessionId1);
verify(mockListener).onSessionActive(adEventTime1, adSessionId1); verify(mockListener).onSessionActive(adEventTime1, adSessionId1);
...@@ -858,6 +866,8 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -858,6 +866,8 @@ public final class DefaultPlaybackSessionManagerTest {
verify(mockListener) verify(mockListener)
.onSessionFinished( .onSessionFinished(
contentEventTime, adSessionId1, /* automaticTransitionToNextPlayback= */ true); contentEventTime, adSessionId1, /* automaticTransitionToNextPlayback= */ true);
verify(mockListener).onSessionCreated(eq(contentEventTime), anyString());
verify(mockListener).onSessionActive(eq(contentEventTime), anyString());
verifyNoMoreInteractions(mockListener); verifyNoMoreInteractions(mockListener);
} }
...@@ -908,6 +918,7 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -908,6 +918,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager.handlePositionDiscontinuity( sessionManager.handlePositionDiscontinuity(
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());
} }
...@@ -964,7 +975,9 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -964,7 +975,9 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager.handlePositionDiscontinuity( sessionManager.handlePositionDiscontinuity(
adEventTime1, Player.DISCONTINUITY_REASON_AD_INSERTION); adEventTime1, Player.DISCONTINUITY_REASON_AD_INSERTION);
sessionManager.updateSessions(adEventTime1);
sessionManager.handlePositionDiscontinuity(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());
...@@ -1034,8 +1047,10 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -1034,8 +1047,10 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager.updateSessions(adEventTime1); sessionManager.updateSessions(adEventTime1);
sessionManager.handlePositionDiscontinuity( sessionManager.handlePositionDiscontinuity(
adEventTime1, Player.DISCONTINUITY_REASON_AD_INSERTION); adEventTime1, Player.DISCONTINUITY_REASON_AD_INSERTION);
sessionManager.updateSessions(adEventTime1);
sessionManager.handlePositionDiscontinuity( sessionManager.handlePositionDiscontinuity(
contentEventTime2, Player.DISCONTINUITY_REASON_AD_INSERTION); contentEventTime2, Player.DISCONTINUITY_REASON_AD_INSERTION);
sessionManager.updateSessions(contentEventTime2);
String adSessionId2 = String adSessionId2 =
sessionManager.getSessionForMediaPeriodId(adTimeline, adEventTime2.mediaPeriodId); sessionManager.getSessionForMediaPeriodId(adTimeline, adEventTime2.mediaPeriodId);
...@@ -1044,6 +1059,31 @@ public final class DefaultPlaybackSessionManagerTest { ...@@ -1044,6 +1059,31 @@ public final class DefaultPlaybackSessionManagerTest {
verify(mockListener, never()).onSessionActive(any(), eq(adSessionId2)); verify(mockListener, never()).onSessionActive(any(), eq(adSessionId2));
} }
@Test
public void finishAllSessions_callsOnSessionFinishedForAllCreatedSessions() {
Timeline timeline = new FakeTimeline(/* windowCount= */ 4);
EventTime eventTimeWindow0 =
createEventTime(timeline, /* windowIndex= */ 0, /* mediaPeriodId= */ null);
EventTime eventTimeWindow2 =
createEventTime(timeline, /* windowIndex= */ 2, /* mediaPeriodId= */ null);
// Actually create sessions for window 0 and 2.
sessionManager.updateSessions(eventTimeWindow0);
sessionManager.updateSessions(eventTimeWindow2);
// Query information about session for window 1, but don't create it.
sessionManager.getSessionForMediaPeriodId(
timeline,
new MediaPeriodId(
timeline.getPeriod(/* periodIndex= */ 1, new Timeline.Period(), /* setIds= */ true).uid,
/* windowSequenceNumber= */ 123));
verify(mockListener, times(2)).onSessionCreated(any(), anyString());
EventTime finishEventTime =
createEventTime(Timeline.EMPTY, /* windowIndex= */ 0, /* mediaPeriodId= */ null);
sessionManager.finishAllSessions(finishEventTime);
verify(mockListener, times(2)).onSessionFinished(eq(finishEventTime), anyString(), eq(false));
}
private static EventTime createEventTime( private static EventTime createEventTime(
Timeline timeline, int windowIndex, @Nullable MediaPeriodId mediaPeriodId) { Timeline timeline, int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
return new EventTime( return new EventTime(
......
...@@ -16,11 +16,20 @@ ...@@ -16,11 +16,20 @@
package com.google.android.exoplayer2.analytics; package com.google.android.exoplayer2.analytics;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.os.SystemClock;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.testutil.FakeTimeline;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
...@@ -28,7 +37,7 @@ import org.junit.runner.RunWith; ...@@ -28,7 +37,7 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public final class PlaybackStatsListenerTest { public final class PlaybackStatsListenerTest {
private static final AnalyticsListener.EventTime TEST_EVENT_TIME = private static final AnalyticsListener.EventTime EMPTY_TIMELINE_EVENT_TIME =
new AnalyticsListener.EventTime( new AnalyticsListener.EventTime(
/* realtimeMs= */ 500, /* realtimeMs= */ 500,
Timeline.EMPTY, Timeline.EMPTY,
...@@ -37,6 +46,41 @@ public final class PlaybackStatsListenerTest { ...@@ -37,6 +46,41 @@ public final class PlaybackStatsListenerTest {
/* eventPlaybackPositionMs= */ 0, /* eventPlaybackPositionMs= */ 0,
/* currentPlaybackPositionMs= */ 0, /* currentPlaybackPositionMs= */ 0,
/* totalBufferedDurationMs= */ 0); /* totalBufferedDurationMs= */ 0);
private static final Timeline TEST_TIMELINE = new FakeTimeline(/* windowCount= */ 1);
private static final AnalyticsListener.EventTime TEST_EVENT_TIME =
new AnalyticsListener.EventTime(
/* realtimeMs= */ 500,
TEST_TIMELINE,
/* windowIndex= */ 0,
new MediaSource.MediaPeriodId(
TEST_TIMELINE.getPeriod(
/* periodIndex= */ 0, new Timeline.Period(), /* setIds= */ true)
.uid,
/* windowSequenceNumber= */ 42),
/* eventPlaybackPositionMs= */ 123,
/* currentPlaybackPositionMs= */ 123,
/* totalBufferedDurationMs= */ 456);
@Test
public void stateChangeEvent_toNonIdle_createsInitialPlaybackStats() {
PlaybackStatsListener playbackStatsListener =
new PlaybackStatsListener(/* keepHistory= */ true, /* callback= */ null);
playbackStatsListener.onPlayerStateChanged(
EMPTY_TIMELINE_EVENT_TIME, /* playWhenReady= */ false, Player.STATE_BUFFERING);
assertThat(playbackStatsListener.getPlaybackStats()).isNotNull();
}
@Test
public void timelineChangeEvent_toNonEmpty_createsInitialPlaybackStats() {
PlaybackStatsListener playbackStatsListener =
new PlaybackStatsListener(/* keepHistory= */ true, /* callback= */ null);
playbackStatsListener.onTimelineChanged(TEST_EVENT_TIME, Player.TIMELINE_CHANGE_REASON_DYNAMIC);
assertThat(playbackStatsListener.getPlaybackStats()).isNotNull();
}
@Test @Test
public void playback_withKeepHistory_updatesStats() { public void playback_withKeepHistory_updatesStats() {
...@@ -71,4 +115,72 @@ public final class PlaybackStatsListenerTest { ...@@ -71,4 +115,72 @@ public final class PlaybackStatsListenerTest {
assertThat(playbackStats).isNotNull(); assertThat(playbackStats).isNotNull();
assertThat(playbackStats.endedCount).isEqualTo(1); assertThat(playbackStats.endedCount).isEqualTo(1);
} }
@Test
public void finishedSession_callsCallback() {
PlaybackStatsListener.Callback callback = mock(PlaybackStatsListener.Callback.class);
PlaybackStatsListener playbackStatsListener =
new PlaybackStatsListener(/* keepHistory= */ true, callback);
// Create session with an event and finish it by simulating removal from playlist.
playbackStatsListener.onPlayerStateChanged(
TEST_EVENT_TIME, /* playWhenReady= */ false, Player.STATE_BUFFERING);
verify(callback, never()).onPlaybackStatsReady(any(), any());
playbackStatsListener.onTimelineChanged(
EMPTY_TIMELINE_EVENT_TIME, Player.TIMELINE_CHANGE_REASON_DYNAMIC);
verify(callback).onPlaybackStatsReady(eq(TEST_EVENT_TIME), any());
}
@Test
public void finishAllSessions_callsAllPendingCallbacks() {
AnalyticsListener.EventTime eventTimeWindow0 =
new AnalyticsListener.EventTime(
/* realtimeMs= */ 0,
Timeline.EMPTY,
/* windowIndex= */ 0,
/* mediaPeriodId= */ null,
/* eventPlaybackPositionMs= */ 0,
/* currentPlaybackPositionMs= */ 0,
/* totalBufferedDurationMs= */ 0);
AnalyticsListener.EventTime eventTimeWindow1 =
new AnalyticsListener.EventTime(
/* realtimeMs= */ 0,
Timeline.EMPTY,
/* windowIndex= */ 1,
/* mediaPeriodId= */ null,
/* eventPlaybackPositionMs= */ 0,
/* currentPlaybackPositionMs= */ 0,
/* totalBufferedDurationMs= */ 0);
PlaybackStatsListener.Callback callback = mock(PlaybackStatsListener.Callback.class);
PlaybackStatsListener playbackStatsListener =
new PlaybackStatsListener(/* keepHistory= */ true, callback);
playbackStatsListener.onPlayerStateChanged(
eventTimeWindow0, /* playWhenReady= */ false, Player.STATE_BUFFERING);
playbackStatsListener.onPlayerStateChanged(
eventTimeWindow1, /* playWhenReady= */ false, Player.STATE_BUFFERING);
playbackStatsListener.finishAllSessions();
verify(callback, times(2)).onPlaybackStatsReady(any(), any());
verify(callback).onPlaybackStatsReady(eq(eventTimeWindow0), any());
verify(callback).onPlaybackStatsReady(eq(eventTimeWindow1), any());
}
@Test
public void finishAllSessions_doesNotCallCallbackAgainWhenSessionWouldBeAutomaticallyFinished() {
PlaybackStatsListener.Callback callback = mock(PlaybackStatsListener.Callback.class);
PlaybackStatsListener playbackStatsListener =
new PlaybackStatsListener(/* keepHistory= */ true, callback);
playbackStatsListener.onPlayerStateChanged(
TEST_EVENT_TIME, /* playWhenReady= */ false, Player.STATE_BUFFERING);
SystemClock.setCurrentTimeMillis(TEST_EVENT_TIME.realtimeMs + 100);
playbackStatsListener.finishAllSessions();
// Simulate removing the playback item to ensure the session would finish if it hadn't already.
playbackStatsListener.onTimelineChanged(
EMPTY_TIMELINE_EVENT_TIME, Player.TIMELINE_CHANGE_REASON_DYNAMIC);
verify(callback).onPlaybackStatsReady(any(), any());
}
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册