• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.media.metrics;
18 
19 import android.annotation.IntDef;
20 import android.annotation.IntRange;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.os.Bundle;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 
27 import com.android.internal.util.AnnotationValidations;
28 
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.List;
34 import java.util.Objects;
35 
36 /**
37  * This class is used to store playback data.
38  */
39 public final class PlaybackMetrics implements Parcelable {
40     /** Unknown stream source. */
41     public static final int STREAM_SOURCE_UNKNOWN = 0;
42     /** Stream from network. */
43     public static final int STREAM_SOURCE_NETWORK = 1;
44     /** Stream from device. */
45     public static final int STREAM_SOURCE_DEVICE = 2;
46     /** Stream from more than one sources. */
47     public static final int STREAM_SOURCE_MIXED = 3;
48 
49     /** Unknown stream type. */
50     public static final int STREAM_TYPE_UNKNOWN = 0;
51     /** Other stream type. */
52     public static final int STREAM_TYPE_OTHER = 1;
53     /** Progressive stream type. */
54     public static final int STREAM_TYPE_PROGRESSIVE = 2;
55     /** DASH (Dynamic Adaptive Streaming over HTTP) stream type. */
56     public static final int STREAM_TYPE_DASH = 3;
57     /** HLS (HTTP Live Streaming) stream type. */
58     public static final int STREAM_TYPE_HLS = 4;
59     /** SS (HTTP Smooth Streaming) stream type. */
60     public static final int STREAM_TYPE_SS = 5;
61 
62     /** Unknown playback type. */
63     public static final int PLAYBACK_TYPE_UNKNOWN = 0;
64     /** VOD (Video on Demand) playback type. */
65     public static final int PLAYBACK_TYPE_VOD = 1;
66     /** Live playback type. */
67     public static final int PLAYBACK_TYPE_LIVE = 2;
68     /** Other playback type. */
69     public static final int PLAYBACK_TYPE_OTHER = 3;
70 
71     /** DRM is not used. */
72     public static final int DRM_TYPE_NONE = 0;
73     /** Other DRM type. */
74     public static final int DRM_TYPE_OTHER = 1;
75     /** Play ready DRM type. */
76     public static final int DRM_TYPE_PLAY_READY = 2;
77     /** Widevine L1 DRM type. */
78     public static final int DRM_TYPE_WIDEVINE_L1 = 3;
79     /** Widevine L3 DRM type. */
80     public static final int DRM_TYPE_WIDEVINE_L3 = 4;
81     /** Widevine L3 fallback DRM type. */
82     public static final int DRM_TYPE_WV_L3_FALLBACK = 5;
83     /** Clear key DRM type. */
84     public static final int DRM_TYPE_CLEARKEY = 6;
85 
86     /** Unknown content type. */
87     public static final int CONTENT_TYPE_UNKNOWN = 0;
88     /** Main contents. */
89     public static final int CONTENT_TYPE_MAIN = 1;
90     /** Advertisement contents. */
91     public static final int CONTENT_TYPE_AD = 2;
92     /** Other contents. */
93     public static final int CONTENT_TYPE_OTHER = 3;
94 
95 
96     /** @hide */
97     @IntDef(prefix = "STREAM_SOURCE_", value = {
98         STREAM_SOURCE_UNKNOWN,
99         STREAM_SOURCE_NETWORK,
100         STREAM_SOURCE_DEVICE,
101         STREAM_SOURCE_MIXED
102     })
103     @Retention(RetentionPolicy.SOURCE)
104     public @interface StreamSource {}
105 
106     /** @hide */
107     @IntDef(prefix = "STREAM_TYPE_", value = {
108         STREAM_TYPE_UNKNOWN,
109         STREAM_TYPE_OTHER,
110         STREAM_TYPE_PROGRESSIVE,
111         STREAM_TYPE_DASH,
112         STREAM_TYPE_HLS,
113         STREAM_TYPE_SS
114     })
115     @Retention(RetentionPolicy.SOURCE)
116     public @interface StreamType {}
117 
118     /** @hide */
119     @IntDef(prefix = "PLAYBACK_TYPE_", value = {
120         PLAYBACK_TYPE_UNKNOWN,
121         PLAYBACK_TYPE_VOD,
122         PLAYBACK_TYPE_LIVE,
123         PLAYBACK_TYPE_OTHER
124     })
125     @Retention(RetentionPolicy.SOURCE)
126     public @interface PlaybackType {}
127 
128     /** @hide */
129     @IntDef(prefix = "DRM_TYPE_", value = {
130         DRM_TYPE_NONE,
131         DRM_TYPE_OTHER,
132         DRM_TYPE_PLAY_READY,
133         DRM_TYPE_WIDEVINE_L1,
134         DRM_TYPE_WIDEVINE_L3,
135         DRM_TYPE_WV_L3_FALLBACK,
136         DRM_TYPE_CLEARKEY
137     })
138     @Retention(RetentionPolicy.SOURCE)
139     public @interface DrmType {}
140 
141     /** @hide */
142     @IntDef(prefix = "CONTENT_TYPE_", value = {
143         CONTENT_TYPE_UNKNOWN,
144         CONTENT_TYPE_MAIN,
145         CONTENT_TYPE_AD,
146         CONTENT_TYPE_OTHER
147     })
148     @Retention(RetentionPolicy.SOURCE)
149     public @interface ContentType {}
150 
151 
152 
153     private final long mMediaDurationMillis;
154     private final int mStreamSource;
155     private final int mStreamType;
156     private final int mPlaybackType;
157     private final int mDrmType;
158     private final int mContentType;
159     private final @Nullable String mPlayerName;
160     private final @Nullable String mPlayerVersion;
161     private final @NonNull long[] mExperimentIds;
162     private final int mVideoFramesPlayed;
163     private final int mVideoFramesDropped;
164     private final int mAudioUnderrunCount;
165     private final long mNetworkBytesRead;
166     private final long mLocalBytesRead;
167     private final long mNetworkTransferDurationMillis;
168     private final byte[] mDrmSessionId;
169     private final @NonNull Bundle mMetricsBundle;
170 
171     /**
172      * Creates a new PlaybackMetrics.
173      *
174      * @hide
175      */
PlaybackMetrics( long mediaDurationMillis, int streamSource, int streamType, int playbackType, int drmType, int contentType, @Nullable String playerName, @Nullable String playerVersion, @NonNull long[] experimentIds, int videoFramesPlayed, int videoFramesDropped, int audioUnderrunCount, long networkBytesRead, long localBytesRead, long networkTransferDurationMillis, byte[] drmSessionId, @NonNull Bundle extras)176     public PlaybackMetrics(
177             long mediaDurationMillis,
178             int streamSource,
179             int streamType,
180             int playbackType,
181             int drmType,
182             int contentType,
183             @Nullable String playerName,
184             @Nullable String playerVersion,
185             @NonNull long[] experimentIds,
186             int videoFramesPlayed,
187             int videoFramesDropped,
188             int audioUnderrunCount,
189             long networkBytesRead,
190             long localBytesRead,
191             long networkTransferDurationMillis,
192             byte[] drmSessionId,
193             @NonNull Bundle extras) {
194         this.mMediaDurationMillis = mediaDurationMillis;
195         this.mStreamSource = streamSource;
196         this.mStreamType = streamType;
197         this.mPlaybackType = playbackType;
198         this.mDrmType = drmType;
199         this.mContentType = contentType;
200         this.mPlayerName = playerName;
201         this.mPlayerVersion = playerVersion;
202         this.mExperimentIds = experimentIds;
203         AnnotationValidations.validate(NonNull.class, null, mExperimentIds);
204         this.mVideoFramesPlayed = videoFramesPlayed;
205         this.mVideoFramesDropped = videoFramesDropped;
206         this.mAudioUnderrunCount = audioUnderrunCount;
207         this.mNetworkBytesRead = networkBytesRead;
208         this.mLocalBytesRead = localBytesRead;
209         this.mNetworkTransferDurationMillis = networkTransferDurationMillis;
210         this.mDrmSessionId = drmSessionId;
211         this.mMetricsBundle = extras.deepCopy();
212     }
213 
214     /**
215      * Gets the media duration in milliseconds.
216      * <p>Media duration is the length of the media.
217      * @return the media duration in milliseconds, or -1 if unknown.
218      */
219     @IntRange(from = -1)
getMediaDurationMillis()220     public long getMediaDurationMillis() {
221         return mMediaDurationMillis;
222     }
223 
224     /**
225      * Gets stream source type.
226      */
227     @StreamSource
getStreamSource()228     public int getStreamSource() {
229         return mStreamSource;
230     }
231 
232     /**
233      * Gets stream type.
234      */
235     @StreamType
getStreamType()236     public int getStreamType() {
237         return mStreamType;
238     }
239 
240 
241     /**
242      * Gets playback type.
243      */
244     @PlaybackType
getPlaybackType()245     public int getPlaybackType() {
246         return mPlaybackType;
247     }
248 
249     /**
250      * Gets DRM type.
251      */
252     @DrmType
getDrmType()253     public int getDrmType() {
254         return mDrmType;
255     }
256 
257     /**
258      * Gets content type.
259      */
260     @ContentType
getContentType()261     public int getContentType() {
262         return mContentType;
263     }
264 
265     /**
266      * Gets player name.
267      */
getPlayerName()268     public @Nullable String getPlayerName() {
269         return mPlayerName;
270     }
271 
272     /**
273      * Gets player version.
274      */
getPlayerVersion()275     public @Nullable String getPlayerVersion() {
276         return mPlayerVersion;
277     }
278 
279     /**
280      * Gets experiment IDs.
281      */
getExperimentIds()282     public @NonNull long[] getExperimentIds() {
283         return Arrays.copyOf(mExperimentIds, mExperimentIds.length);
284     }
285 
286     /**
287      * Gets video frames played.
288      * @return the video frames played, or -1 if unknown.
289      */
290     @IntRange(from = -1, to = Integer.MAX_VALUE)
getVideoFramesPlayed()291     public int getVideoFramesPlayed() {
292         return mVideoFramesPlayed;
293     }
294 
295     /**
296      * Gets video frames dropped.
297      * @return the video frames dropped, or -1 if unknown.
298      */
299     @IntRange(from = -1, to = Integer.MAX_VALUE)
getVideoFramesDropped()300     public int getVideoFramesDropped() {
301         return mVideoFramesDropped;
302     }
303 
304     /**
305      * Gets audio underrun count.
306      * @return the audio underrun count, or -1 if unknown.
307      */
308     @IntRange(from = -1, to = Integer.MAX_VALUE)
getAudioUnderrunCount()309     public int getAudioUnderrunCount() {
310         return mAudioUnderrunCount;
311     }
312 
313     /**
314      * Gets number of network bytes read.
315      * @return the number of network bytes read, or -1 if unknown.
316      */
317     @IntRange(from = -1)
getNetworkBytesRead()318     public long getNetworkBytesRead() {
319         return mNetworkBytesRead;
320     }
321 
322     /**
323      * Gets number of local bytes read.
324      */
325     @IntRange(from = -1)
getLocalBytesRead()326     public long getLocalBytesRead() {
327         return mLocalBytesRead;
328     }
329 
330     /**
331      * Gets network transfer duration in milliseconds.
332      * <p>Total transfer time spent reading from the network in ms. For parallel requests, the
333      * overlapping time intervals are counted only once.
334      */
335     @IntRange(from = -1)
getNetworkTransferDurationMillis()336     public long getNetworkTransferDurationMillis() {
337         return mNetworkTransferDurationMillis;
338     }
339 
340     /**
341      * Gets DRM session ID.
342      */
343     @NonNull
getDrmSessionId()344     public byte[] getDrmSessionId() {
345         return mDrmSessionId;
346     }
347 
348     /**
349      * Gets metrics-related information that is not supported by dedicated methods.
350      * <p>It is intended to be used for backwards compatibility by the metrics infrastructure.
351      */
352     @NonNull
getMetricsBundle()353     public Bundle getMetricsBundle() {
354         return mMetricsBundle;
355     }
356 
357     @Override
toString()358     public String toString() {
359         return "PlaybackMetrics { "
360                 + "mediaDurationMillis = " + mMediaDurationMillis + ", "
361                 + "streamSource = " + mStreamSource + ", "
362                 + "streamType = " + mStreamType + ", "
363                 + "playbackType = " + mPlaybackType + ", "
364                 + "drmType = " + mDrmType + ", "
365                 + "contentType = " + mContentType + ", "
366                 + "playerName = " + mPlayerName + ", "
367                 + "playerVersion = " + mPlayerVersion + ", "
368                 + "experimentIds = " + Arrays.toString(mExperimentIds) + ", "
369                 + "videoFramesPlayed = " + mVideoFramesPlayed + ", "
370                 + "videoFramesDropped = " + mVideoFramesDropped + ", "
371                 + "audioUnderrunCount = " + mAudioUnderrunCount + ", "
372                 + "networkBytesRead = " + mNetworkBytesRead + ", "
373                 + "localBytesRead = " + mLocalBytesRead + ", "
374                 + "networkTransferDurationMillis = " + mNetworkTransferDurationMillis
375                 + "drmSessionId = " + Arrays.toString(mDrmSessionId)
376                 + " }";
377     }
378 
379     @Override
equals(@ullable Object o)380     public boolean equals(@Nullable Object o) {
381         if (this == o) return true;
382         if (o == null || getClass() != o.getClass()) return false;
383         PlaybackMetrics that = (PlaybackMetrics) o;
384         return mMediaDurationMillis == that.mMediaDurationMillis
385                 && mStreamSource == that.mStreamSource
386                 && mStreamType == that.mStreamType
387                 && mPlaybackType == that.mPlaybackType
388                 && mDrmType == that.mDrmType
389                 && mContentType == that.mContentType
390                 && Objects.equals(mPlayerName, that.mPlayerName)
391                 && Objects.equals(mPlayerVersion, that.mPlayerVersion)
392                 && Arrays.equals(mExperimentIds, that.mExperimentIds)
393                 && mVideoFramesPlayed == that.mVideoFramesPlayed
394                 && mVideoFramesDropped == that.mVideoFramesDropped
395                 && mAudioUnderrunCount == that.mAudioUnderrunCount
396                 && mNetworkBytesRead == that.mNetworkBytesRead
397                 && mLocalBytesRead == that.mLocalBytesRead
398                 && mNetworkTransferDurationMillis == that.mNetworkTransferDurationMillis
399                 && Arrays.equals(mDrmSessionId, that.mDrmSessionId);
400     }
401 
402     @Override
hashCode()403     public int hashCode() {
404         return Objects.hash(mMediaDurationMillis, mStreamSource, mStreamType, mPlaybackType,
405                 mDrmType, mContentType, mPlayerName, mPlayerVersion, mExperimentIds,
406                 mVideoFramesPlayed, mVideoFramesDropped, mAudioUnderrunCount, mNetworkBytesRead,
407                 mLocalBytesRead, mNetworkTransferDurationMillis, mDrmSessionId);
408     }
409 
410     @Override
writeToParcel(@onNull Parcel dest, int flags)411     public void writeToParcel(@NonNull Parcel dest, int flags) {
412         long flg = 0;
413         if (mPlayerName != null) flg |= 0x80;
414         if (mPlayerVersion != null) flg |= 0x100;
415         dest.writeLong(flg);
416         dest.writeLong(mMediaDurationMillis);
417         dest.writeInt(mStreamSource);
418         dest.writeInt(mStreamType);
419         dest.writeInt(mPlaybackType);
420         dest.writeInt(mDrmType);
421         dest.writeInt(mContentType);
422         if (mPlayerName != null) dest.writeString(mPlayerName);
423         if (mPlayerVersion != null) dest.writeString(mPlayerVersion);
424         dest.writeLongArray(mExperimentIds);
425         dest.writeInt(mVideoFramesPlayed);
426         dest.writeInt(mVideoFramesDropped);
427         dest.writeInt(mAudioUnderrunCount);
428         dest.writeLong(mNetworkBytesRead);
429         dest.writeLong(mLocalBytesRead);
430         dest.writeLong(mNetworkTransferDurationMillis);
431         dest.writeInt(mDrmSessionId.length);
432         dest.writeByteArray(mDrmSessionId);
433         dest.writeBundle(mMetricsBundle);
434     }
435 
436     @Override
describeContents()437     public int describeContents() {
438         return 0;
439     }
440 
441     /** @hide */
PlaybackMetrics(@onNull Parcel in)442     /* package-private */ PlaybackMetrics(@NonNull Parcel in) {
443         long flg = in.readLong();
444         long mediaDurationMillis = in.readLong();
445         int streamSource = in.readInt();
446         int streamType = in.readInt();
447         int playbackType = in.readInt();
448         int drmType = in.readInt();
449         int contentType = in.readInt();
450         String playerName = (flg & 0x80) == 0 ? null : in.readString();
451         String playerVersion = (flg & 0x100) == 0 ? null : in.readString();
452         long[] experimentIds = in.createLongArray();
453         int videoFramesPlayed = in.readInt();
454         int videoFramesDropped = in.readInt();
455         int audioUnderrunCount = in.readInt();
456         long networkBytesRead = in.readLong();
457         long localBytesRead = in.readLong();
458         long networkTransferDurationMillis = in.readLong();
459         int drmSessionIdLen = in.readInt();
460         byte[] drmSessionId = new byte[drmSessionIdLen];
461         in.readByteArray(drmSessionId);
462         Bundle extras = in.readBundle();
463 
464         this.mMediaDurationMillis = mediaDurationMillis;
465         this.mStreamSource = streamSource;
466         this.mStreamType = streamType;
467         this.mPlaybackType = playbackType;
468         this.mDrmType = drmType;
469         this.mContentType = contentType;
470         this.mPlayerName = playerName;
471         this.mPlayerVersion = playerVersion;
472         this.mExperimentIds = experimentIds;
473         AnnotationValidations.validate(NonNull.class, null, mExperimentIds);
474         this.mVideoFramesPlayed = videoFramesPlayed;
475         this.mVideoFramesDropped = videoFramesDropped;
476         this.mAudioUnderrunCount = audioUnderrunCount;
477         this.mNetworkBytesRead = networkBytesRead;
478         this.mLocalBytesRead = localBytesRead;
479         this.mNetworkTransferDurationMillis = networkTransferDurationMillis;
480         this.mDrmSessionId = drmSessionId;
481         this.mMetricsBundle = extras;
482     }
483 
484     public static final @NonNull Parcelable.Creator<PlaybackMetrics> CREATOR =
485             new Parcelable.Creator<PlaybackMetrics>() {
486         @Override
487         public PlaybackMetrics[] newArray(int size) {
488             return new PlaybackMetrics[size];
489         }
490 
491         @Override
492         public PlaybackMetrics createFromParcel(@NonNull Parcel in) {
493             return new PlaybackMetrics(in);
494         }
495     };
496 
497     /**
498      * A builder for {@link PlaybackMetrics}
499      */
500     public static final class Builder {
501 
502         private long mMediaDurationMillis = -1;
503         private int mStreamSource = STREAM_SOURCE_UNKNOWN;
504         private int mStreamType = STREAM_TYPE_UNKNOWN;
505         private int mPlaybackType = PLAYBACK_TYPE_UNKNOWN;
506         private int mDrmType = DRM_TYPE_NONE;
507         private int mContentType = CONTENT_TYPE_UNKNOWN;
508         private @Nullable String mPlayerName;
509         private @Nullable String mPlayerVersion;
510         private @NonNull List<Long> mExperimentIds = new ArrayList<>();
511         private int mVideoFramesPlayed = -1;
512         private int mVideoFramesDropped = -1;
513         private int mAudioUnderrunCount = -1;
514         private long mNetworkBytesRead = -1;
515         private long mLocalBytesRead = -1;
516         private long mNetworkTransferDurationMillis = -1;
517         private byte[] mDrmSessionId = new byte[0];
518         private Bundle mMetricsBundle = new Bundle();
519 
520         /**
521          * Creates a new Builder.
522          */
Builder()523         public Builder() {
524         }
525 
526         /**
527          * Sets the media duration in milliseconds.
528          * @param value the media duration in milliseconds. -1 indicates the value is unknown.
529          * @see #getMediaDurationMillis()
530          */
setMediaDurationMillis(@ntRangefrom = -1) long value)531         public @NonNull Builder setMediaDurationMillis(@IntRange(from = -1) long value) {
532             mMediaDurationMillis = value;
533             return this;
534         }
535 
536         /**
537          * Sets the stream source type.
538          */
setStreamSource(@treamSource int value)539         public @NonNull Builder setStreamSource(@StreamSource int value) {
540             mStreamSource = value;
541             return this;
542         }
543 
544         /**
545          * Sets the stream type.
546          */
setStreamType(@treamType int value)547         public @NonNull Builder setStreamType(@StreamType int value) {
548             mStreamType = value;
549             return this;
550         }
551 
552         /**
553          * Sets the playback type.
554          */
setPlaybackType(@laybackType int value)555         public @NonNull Builder setPlaybackType(@PlaybackType int value) {
556             mPlaybackType = value;
557             return this;
558         }
559 
560         /**
561          * Sets the DRM type.
562          */
setDrmType(@rmType int value)563         public @NonNull Builder setDrmType(@DrmType int value) {
564             mDrmType = value;
565             return this;
566         }
567 
568         /**
569          * Sets the content type.
570          */
setContentType(@ontentType int value)571         public @NonNull Builder setContentType(@ContentType int value) {
572             mContentType = value;
573             return this;
574         }
575 
576         /**
577          * Sets the player name.
578          */
setPlayerName(@onNull String value)579         public @NonNull Builder setPlayerName(@NonNull String value) {
580             mPlayerName = value;
581             return this;
582         }
583 
584         /**
585          * Sets the player version.
586          */
setPlayerVersion(@onNull String value)587         public @NonNull Builder setPlayerVersion(@NonNull String value) {
588             mPlayerVersion = value;
589             return this;
590         }
591 
592         /**
593          * Adds the experiment ID.
594          */
addExperimentId(long value)595         public @NonNull Builder addExperimentId(long value) {
596             mExperimentIds.add(value);
597             return this;
598         }
599 
600         /**
601          * Sets the video frames played.
602          * @param value the video frames played. -1 indicates the value is unknown.
603          */
setVideoFramesPlayed( @ntRangefrom = -1, to = Integer.MAX_VALUE) int value)604         public @NonNull Builder setVideoFramesPlayed(
605                 @IntRange(from = -1, to = Integer.MAX_VALUE) int value) {
606             mVideoFramesPlayed = value;
607             return this;
608         }
609 
610         /**
611          * Sets the video frames dropped.
612          * @param value the video frames dropped. -1 indicates the value is unknown.
613          */
setVideoFramesDropped( @ntRangefrom = -1, to = Integer.MAX_VALUE) int value)614         public @NonNull Builder setVideoFramesDropped(
615                 @IntRange(from = -1, to = Integer.MAX_VALUE) int value) {
616             mVideoFramesDropped = value;
617             return this;
618         }
619 
620         /**
621          * Sets the audio underrun count.
622          * @param value the audio underrun count. -1 indicates the value is unknown.
623          */
setAudioUnderrunCount( @ntRangefrom = -1, to = Integer.MAX_VALUE) int value)624         public @NonNull Builder setAudioUnderrunCount(
625                 @IntRange(from = -1, to = Integer.MAX_VALUE) int value) {
626             mAudioUnderrunCount = value;
627             return this;
628         }
629 
630         /**
631          * Sets the number of network bytes read.
632          * @param value the number of network bytes read. -1 indicates the value is unknown.
633          */
setNetworkBytesRead(@ntRangefrom = -1) long value)634         public @NonNull Builder setNetworkBytesRead(@IntRange(from = -1) long value) {
635             mNetworkBytesRead = value;
636             return this;
637         }
638 
639         /**
640          * Sets the number of local bytes read.
641          * @param value the number of local bytes read. -1 indicates the value is unknown.
642          */
setLocalBytesRead(@ntRangefrom = -1) long value)643         public @NonNull Builder setLocalBytesRead(@IntRange(from = -1) long value) {
644             mLocalBytesRead = value;
645             return this;
646         }
647 
648         /**
649          * Sets the network transfer duration in milliseconds.
650          * @param value the network transfer duration in milliseconds.
651          *              -1 indicates the value is unknown.
652          * @see #getNetworkTransferDurationMillis()
653          */
setNetworkTransferDurationMillis(@ntRangefrom = -1) long value)654         public @NonNull Builder setNetworkTransferDurationMillis(@IntRange(from = -1) long value) {
655             mNetworkTransferDurationMillis = value;
656             return this;
657         }
658 
659         /**
660          * Sets DRM session ID.
661          */
setDrmSessionId(@onNull byte[] drmSessionId)662         public @NonNull Builder setDrmSessionId(@NonNull byte[] drmSessionId) {
663             mDrmSessionId = drmSessionId;
664             return this;
665         }
666 
667         /**
668          * Sets metrics-related information that is not supported by dedicated
669          * methods.
670          * <p>It is intended to be used for backwards compatibility by the
671          * metrics infrastructure.
672          */
setMetricsBundle(@onNull Bundle metricsBundle)673         public @NonNull Builder setMetricsBundle(@NonNull Bundle metricsBundle) {
674             mMetricsBundle = metricsBundle;
675             return this;
676         }
677 
678         /** Builds the instance. This builder should not be touched after calling this! */
build()679         public @NonNull PlaybackMetrics build() {
680 
681             PlaybackMetrics o = new PlaybackMetrics(
682                     mMediaDurationMillis,
683                     mStreamSource,
684                     mStreamType,
685                     mPlaybackType,
686                     mDrmType,
687                     mContentType,
688                     mPlayerName,
689                     mPlayerVersion,
690                     idsToLongArray(),
691                     mVideoFramesPlayed,
692                     mVideoFramesDropped,
693                     mAudioUnderrunCount,
694                     mNetworkBytesRead,
695                     mLocalBytesRead,
696                     mNetworkTransferDurationMillis,
697                     mDrmSessionId,
698                     mMetricsBundle);
699             return o;
700         }
701 
idsToLongArray()702         private long[] idsToLongArray() {
703             long[] ids = new long[mExperimentIds.size()];
704             for (int i = 0; i < mExperimentIds.size(); i++) {
705                 ids[i] = mExperimentIds.get(i);
706             }
707             return ids;
708         }
709     }
710 }
711