Release all PlaybackStatsListener session when timeline becomes empty.

Currently they are only released when the timeline becomes non-empty
again or the player is released.

Issue: #8778
PiperOrigin-RevId: 366041625
This commit is contained in:
marcbaechinger 2021-04-09 18:27:51 +01:00
parent e6780bd157
commit 6d0a04dd87
2 changed files with 35 additions and 6 deletions

View File

@ -293,18 +293,16 @@ public final class PlaybackStatsListener
}
private void maybeAddSessions(Player player, Events events) {
if (player.getCurrentTimeline().isEmpty() && player.getPlaybackState() == Player.STATE_IDLE) {
// Player is completely idle. Don't add new sessions.
return;
}
boolean isCompletelyIdle =
player.getCurrentTimeline().isEmpty() && player.getPlaybackState() == Player.STATE_IDLE;
for (int i = 0; i < events.size(); i++) {
@EventFlags int event = events.get(i);
EventTime eventTime = events.getEventTime(event);
if (event == EVENT_TIMELINE_CHANGED) {
sessionManager.updateSessionsWithTimelineChange(eventTime);
} else if (event == EVENT_POSITION_DISCONTINUITY) {
} else if (!isCompletelyIdle && event == EVENT_POSITION_DISCONTINUITY) {
sessionManager.updateSessionsWithDiscontinuity(eventTime, discontinuityReason);
} else {
} else if (!isCompletelyIdle) {
sessionManager.updateSessions(eventTime);
}
}

View File

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.analytics;
import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.runUntilPendingCommandsAreFullyHandled;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
@ -42,6 +43,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.robolectric.shadows.ShadowLooper;
/** Unit test for {@link PlaybackStatsListener}. */
@RunWith(AndroidJUnit4.class)
@ -151,6 +153,35 @@ public final class PlaybackStatsListenerTest {
verify(callback).onPlaybackStatsReady(any(), any());
}
@Test
public void playlistClear_callsAllPendingCallbacks() throws Exception {
PlaybackStatsListener.Callback callback = mock(PlaybackStatsListener.Callback.class);
PlaybackStatsListener playbackStatsListener =
new PlaybackStatsListener(/* keepHistory= */ true, callback);
player.addAnalyticsListener(playbackStatsListener);
MediaSource mediaSource = new FakeMediaSource(new FakeTimeline(/* windowCount= */ 1));
player.setMediaSources(ImmutableList.of(mediaSource, mediaSource));
player.prepare();
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_READY);
// Play close to the end of the first item to ensure the second session is already created, but
// the first one isn't finished yet.
TestPlayerRunHelper.playUntilPosition(
player, /* windowIndex= */ 0, /* positionMs= */ player.getDuration());
runUntilPendingCommandsAreFullyHandled(player);
player.clearMediaItems();
ShadowLooper.idleMainLooper();
ArgumentCaptor<AnalyticsListener.EventTime> eventTimeCaptor =
ArgumentCaptor.forClass(AnalyticsListener.EventTime.class);
verify(callback, times(2)).onPlaybackStatsReady(eventTimeCaptor.capture(), any());
assertThat(
eventTimeCaptor.getAllValues().stream()
.map(eventTime -> eventTime.windowIndex)
.collect(Collectors.toList()))
.containsExactly(0, 1);
}
@Test
public void playerRelease_callsAllPendingCallbacks() throws Exception {
PlaybackStatsListener.Callback callback = mock(PlaybackStatsListener.Callback.class);