Ensure network transfers are associated with the right session

We currently don't check which session is causing a network transfer
(it could be a preloaded item in a playlist). To clearly associate
network transfer data with sessions, we need to keep track of
transferred bytes and transfer time per session.

PiperOrigin-RevId: 422867845
This commit is contained in:
tonihei 2022-01-19 19:48:59 +00:00 committed by Ian Baker
parent 081700f72b
commit 301fcd649a

View File

@ -75,6 +75,7 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.UUID; import java.util.UUID;
import org.checkerframework.checker.nullness.compatqual.NullableType; import org.checkerframework.checker.nullness.compatqual.NullableType;
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
@ -113,6 +114,8 @@ public final class MediaMetricsListener
private final long startTimeMs; private final long startTimeMs;
private final Timeline.Window window; private final Timeline.Window window;
private final Timeline.Period period; private final Timeline.Period period;
private final HashMap<String, Long> bandwidthTimeMs;
private final HashMap<String, Long> bandwidthBytes;
@Nullable private String activeSessionId; @Nullable private String activeSessionId;
@Nullable private PlaybackMetrics.Builder metricsBuilder; @Nullable private PlaybackMetrics.Builder metricsBuilder;
@ -131,8 +134,6 @@ public final class MediaMetricsListener
private boolean hasFatalError; private boolean hasFatalError;
private int droppedFrames; private int droppedFrames;
private int playedFrames; private int playedFrames;
private long bandwidthTimeMs;
private long bandwidthBytes;
private int audioUnderruns; private int audioUnderruns;
/** /**
@ -146,6 +147,8 @@ public final class MediaMetricsListener
this.playbackSession = playbackSession; this.playbackSession = playbackSession;
window = new Timeline.Window(); window = new Timeline.Window();
period = new Timeline.Period(); period = new Timeline.Period();
bandwidthBytes = new HashMap<>();
bandwidthTimeMs = new HashMap<>();
startTimeMs = SystemClock.elapsedRealtime(); startTimeMs = SystemClock.elapsedRealtime();
currentPlaybackState = PlaybackStateEvent.STATE_NOT_STARTED; currentPlaybackState = PlaybackStateEvent.STATE_NOT_STARTED;
currentNetworkType = NetworkEvent.NETWORK_TYPE_UNKNOWN; currentNetworkType = NetworkEvent.NETWORK_TYPE_UNKNOWN;
@ -188,8 +191,11 @@ public final class MediaMetricsListener
if ((eventTime.mediaPeriodId != null && eventTime.mediaPeriodId.isAd()) if ((eventTime.mediaPeriodId != null && eventTime.mediaPeriodId.isAd())
|| !sessionId.equals(activeSessionId)) { || !sessionId.equals(activeSessionId)) {
// Ignore ad sessions and other sessions that are finished before becoming active. // Ignore ad sessions and other sessions that are finished before becoming active.
} else {
finishCurrentSession();
} }
finishCurrentSession(); bandwidthTimeMs.remove(sessionId);
bandwidthBytes.remove(sessionId);
} }
// AnalyticsListener implementation. // AnalyticsListener implementation.
@ -216,8 +222,17 @@ public final class MediaMetricsListener
@Override @Override
public void onBandwidthEstimate( public void onBandwidthEstimate(
EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate) { EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate) {
bandwidthTimeMs += totalLoadTimeMs; if (eventTime.mediaPeriodId != null) {
bandwidthBytes += totalBytesLoaded; String sessionId =
sessionManager.getSessionForMediaPeriodId(
eventTime.timeline, checkNotNull(eventTime.mediaPeriodId));
@Nullable Long prevBandwidthBytes = bandwidthBytes.get(sessionId);
@Nullable Long prevBandwidthTimeMs = bandwidthTimeMs.get(sessionId);
bandwidthBytes.put(
sessionId, (prevBandwidthBytes == null ? 0 : prevBandwidthBytes) + totalBytesLoaded);
bandwidthTimeMs.put(
sessionId, (prevBandwidthTimeMs == null ? 0 : prevBandwidthTimeMs) + totalLoadTimeMs);
}
} }
@Override @Override
@ -581,12 +596,14 @@ public final class MediaMetricsListener
metricsBuilder.setAudioUnderrunCount(audioUnderruns); metricsBuilder.setAudioUnderrunCount(audioUnderruns);
metricsBuilder.setVideoFramesDropped(droppedFrames); metricsBuilder.setVideoFramesDropped(droppedFrames);
metricsBuilder.setVideoFramesPlayed(playedFrames); metricsBuilder.setVideoFramesPlayed(playedFrames);
metricsBuilder.setNetworkTransferDurationMillis(bandwidthTimeMs); @Nullable Long networkTimeMs = bandwidthTimeMs.get(activeSessionId);
metricsBuilder.setNetworkTransferDurationMillis(networkTimeMs == null ? 0 : networkTimeMs);
// TODO(b/181121847): Report localBytesRead. This requires additional callbacks or plumbing. // TODO(b/181121847): Report localBytesRead. This requires additional callbacks or plumbing.
metricsBuilder.setNetworkBytesRead(bandwidthBytes); @Nullable Long networkBytes = bandwidthBytes.get(activeSessionId);
metricsBuilder.setNetworkBytesRead(networkBytes == null ? 0 : networkBytes);
// TODO(b/181121847): Detect stream sources mixed and local depending on localBytesRead. // TODO(b/181121847): Detect stream sources mixed and local depending on localBytesRead.
metricsBuilder.setStreamSource( metricsBuilder.setStreamSource(
bandwidthBytes > 0 networkBytes != null && networkBytes > 0
? PlaybackMetrics.STREAM_SOURCE_NETWORK ? PlaybackMetrics.STREAM_SOURCE_NETWORK
: PlaybackMetrics.STREAM_SOURCE_UNKNOWN); : PlaybackMetrics.STREAM_SOURCE_UNKNOWN);
playbackSession.reportPlaybackMetrics(metricsBuilder.build()); playbackSession.reportPlaybackMetrics(metricsBuilder.build());