mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Make sure not to create new playback sessions while still IDLE.
The first session should only be created once we have the media items and/or called prepare. Otherwise the first session is created with an EventTime having an empty timeline making it less useful. issue:#7193 PiperOrigin-RevId: 308100555
This commit is contained in:
parent
63db847bf6
commit
e250fe6277
2 changed files with 80 additions and 19 deletions
|
|
@ -245,7 +245,7 @@ public final class PlaybackStatsListener
|
||||||
@Override
|
@Override
|
||||||
public void onPlaybackStateChanged(EventTime eventTime, @Player.State int state) {
|
public void onPlaybackStateChanged(EventTime eventTime, @Player.State int state) {
|
||||||
playbackState = state;
|
playbackState = state;
|
||||||
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
|
||||||
|
|
@ -258,7 +258,7 @@ public final class PlaybackStatsListener
|
||||||
public void onPlayWhenReadyChanged(
|
public void onPlayWhenReadyChanged(
|
||||||
EventTime eventTime, boolean playWhenReady, @Player.PlayWhenReadyChangeReason int reason) {
|
EventTime eventTime, boolean playWhenReady, @Player.PlayWhenReadyChangeReason int reason) {
|
||||||
this.playWhenReady = playWhenReady;
|
this.playWhenReady = playWhenReady;
|
||||||
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
|
||||||
|
|
@ -271,7 +271,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
|
||||||
|
|
@ -283,7 +283,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);
|
||||||
|
|
@ -294,7 +294,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);
|
||||||
|
|
@ -304,7 +304,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()) {
|
||||||
boolean belongsToPlayback = sessionManager.belongsToSession(eventTime, session);
|
boolean belongsToPlayback = sessionManager.belongsToSession(eventTime, session);
|
||||||
playbackStatsTrackers.get(session).onSeekStarted(eventTime, belongsToPlayback);
|
playbackStatsTrackers.get(session).onSeekStarted(eventTime, belongsToPlayback);
|
||||||
|
|
@ -314,7 +314,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()) {
|
||||||
boolean belongsToPlayback = sessionManager.belongsToSession(eventTime, session);
|
boolean belongsToPlayback = sessionManager.belongsToSession(eventTime, session);
|
||||||
playbackStatsTrackers.get(session).onSeekProcessed(eventTime, belongsToPlayback);
|
playbackStatsTrackers.get(session).onSeekProcessed(eventTime, belongsToPlayback);
|
||||||
|
|
@ -324,7 +324,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);
|
||||||
|
|
@ -335,7 +335,7 @@ public final class PlaybackStatsListener
|
||||||
@Override
|
@Override
|
||||||
public void onPlaybackSpeedChanged(EventTime eventTime, float playbackSpeed) {
|
public void onPlaybackSpeedChanged(EventTime eventTime, float playbackSpeed) {
|
||||||
this.playbackSpeed = playbackSpeed;
|
this.playbackSpeed = playbackSpeed;
|
||||||
sessionManager.updateSessions(eventTime);
|
maybeAddSession(eventTime);
|
||||||
for (PlaybackStatsTracker tracker : playbackStatsTrackers.values()) {
|
for (PlaybackStatsTracker tracker : playbackStatsTrackers.values()) {
|
||||||
tracker.onPlaybackSpeedChanged(eventTime, playbackSpeed);
|
tracker.onPlaybackSpeedChanged(eventTime, playbackSpeed);
|
||||||
}
|
}
|
||||||
|
|
@ -344,7 +344,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);
|
||||||
|
|
@ -355,7 +355,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);
|
||||||
|
|
@ -365,7 +365,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);
|
||||||
|
|
@ -380,7 +380,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);
|
||||||
|
|
@ -391,7 +391,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);
|
||||||
|
|
@ -402,7 +402,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();
|
||||||
|
|
@ -412,7 +412,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);
|
||||||
|
|
@ -427,7 +427,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);
|
||||||
|
|
@ -437,7 +437,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);
|
||||||
|
|
@ -445,6 +445,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,8 @@ 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 +30,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 +39,58 @@ 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= */ 700,
|
||||||
|
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 events_duringInitialIdleState_dontCreateNewPlaybackStats() {
|
||||||
|
PlaybackStatsListener playbackStatsListener =
|
||||||
|
new PlaybackStatsListener(/* keepHistory= */ true, /* callback= */ null);
|
||||||
|
|
||||||
|
playbackStatsListener.onPositionDiscontinuity(
|
||||||
|
EMPTY_TIMELINE_EVENT_TIME, Player.DISCONTINUITY_REASON_SEEK);
|
||||||
|
playbackStatsListener.onPlaybackSpeedChanged(
|
||||||
|
EMPTY_TIMELINE_EVENT_TIME, /* playbackSpeed= */ 2.0f);
|
||||||
|
playbackStatsListener.onPlayWhenReadyChanged(
|
||||||
|
EMPTY_TIMELINE_EVENT_TIME,
|
||||||
|
/* playWhenReady= */ true,
|
||||||
|
Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
||||||
|
|
||||||
|
assertThat(playbackStatsListener.getPlaybackStats()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void stateChangeEvent_toNonIdle_createsInitialPlaybackStats() {
|
||||||
|
PlaybackStatsListener playbackStatsListener =
|
||||||
|
new PlaybackStatsListener(/* keepHistory= */ true, /* callback= */ null);
|
||||||
|
|
||||||
|
playbackStatsListener.onPlaybackStateChanged(EMPTY_TIMELINE_EVENT_TIME, 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_PLAYLIST_CHANGED);
|
||||||
|
|
||||||
|
assertThat(playbackStatsListener.getPlaybackStats()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void playback_withKeepHistory_updatesStats() {
|
public void playback_withKeepHistory_updatesStats() {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue