From 8b9d657bffce6fad3897fa735273ef51ab7fa580 Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 19 Jan 2022 19:48:59 +0000 Subject: [PATCH] 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 --- .../analytics/MediaMetricsListener.java | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/MediaMetricsListener.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/MediaMetricsListener.java index f7299c5f2b..a0187d67a9 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/MediaMetricsListener.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/MediaMetricsListener.java @@ -76,6 +76,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; +import java.util.HashMap; import java.util.UUID; import org.checkerframework.checker.nullness.compatqual.NullableType; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; @@ -115,6 +116,8 @@ public final class MediaMetricsListener private final long startTimeMs; private final Timeline.Window window; private final Timeline.Period period; + private final HashMap bandwidthTimeMs; + private final HashMap bandwidthBytes; @Nullable private String activeSessionId; @Nullable private PlaybackMetrics.Builder metricsBuilder; @@ -133,8 +136,6 @@ public final class MediaMetricsListener private boolean hasFatalError; private int droppedFrames; private int playedFrames; - private long bandwidthTimeMs; - private long bandwidthBytes; private int audioUnderruns; /** @@ -148,6 +149,8 @@ public final class MediaMetricsListener this.playbackSession = playbackSession; window = new Timeline.Window(); period = new Timeline.Period(); + bandwidthBytes = new HashMap<>(); + bandwidthTimeMs = new HashMap<>(); startTimeMs = SystemClock.elapsedRealtime(); currentPlaybackState = PlaybackStateEvent.STATE_NOT_STARTED; currentNetworkType = NetworkEvent.NETWORK_TYPE_UNKNOWN; @@ -190,8 +193,11 @@ public final class MediaMetricsListener if ((eventTime.mediaPeriodId != null && eventTime.mediaPeriodId.isAd()) || !sessionId.equals(activeSessionId)) { // Ignore ad sessions and other sessions that are finished before becoming active. + } else { + finishCurrentSession(); } - finishCurrentSession(); + bandwidthTimeMs.remove(sessionId); + bandwidthBytes.remove(sessionId); } // AnalyticsListener implementation. @@ -218,8 +224,17 @@ public final class MediaMetricsListener @Override public void onBandwidthEstimate( EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate) { - bandwidthTimeMs += totalLoadTimeMs; - bandwidthBytes += totalBytesLoaded; + if (eventTime.mediaPeriodId != null) { + 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 @@ -583,12 +598,14 @@ public final class MediaMetricsListener metricsBuilder.setAudioUnderrunCount(audioUnderruns); metricsBuilder.setVideoFramesDropped(droppedFrames); 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. - 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. metricsBuilder.setStreamSource( - bandwidthBytes > 0 + networkBytes != null && networkBytes > 0 ? PlaybackMetrics.STREAM_SOURCE_NETWORK : PlaybackMetrics.STREAM_SOURCE_UNKNOWN); playbackSession.reportPlaybackMetrics(metricsBuilder.build());