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, 406 Arrays.hashCode(mExperimentIds), mVideoFramesPlayed, mVideoFramesDropped, 407 mAudioUnderrunCount, mNetworkBytesRead, mLocalBytesRead, 408 mNetworkTransferDurationMillis, Arrays.hashCode(mDrmSessionId)); 409 } 410 411 @Override writeToParcel(@onNull Parcel dest, int flags)412 public void writeToParcel(@NonNull Parcel dest, int flags) { 413 long flg = 0; 414 if (mPlayerName != null) flg |= 0x80; 415 if (mPlayerVersion != null) flg |= 0x100; 416 dest.writeLong(flg); 417 dest.writeLong(mMediaDurationMillis); 418 dest.writeInt(mStreamSource); 419 dest.writeInt(mStreamType); 420 dest.writeInt(mPlaybackType); 421 dest.writeInt(mDrmType); 422 dest.writeInt(mContentType); 423 if (mPlayerName != null) dest.writeString(mPlayerName); 424 if (mPlayerVersion != null) dest.writeString(mPlayerVersion); 425 dest.writeLongArray(mExperimentIds); 426 dest.writeInt(mVideoFramesPlayed); 427 dest.writeInt(mVideoFramesDropped); 428 dest.writeInt(mAudioUnderrunCount); 429 dest.writeLong(mNetworkBytesRead); 430 dest.writeLong(mLocalBytesRead); 431 dest.writeLong(mNetworkTransferDurationMillis); 432 dest.writeInt(mDrmSessionId.length); 433 dest.writeByteArray(mDrmSessionId); 434 dest.writeBundle(mMetricsBundle); 435 } 436 437 @Override describeContents()438 public int describeContents() { 439 return 0; 440 } 441 442 /** @hide */ PlaybackMetrics(@onNull Parcel in)443 /* package-private */ PlaybackMetrics(@NonNull Parcel in) { 444 long flg = in.readLong(); 445 long mediaDurationMillis = in.readLong(); 446 int streamSource = in.readInt(); 447 int streamType = in.readInt(); 448 int playbackType = in.readInt(); 449 int drmType = in.readInt(); 450 int contentType = in.readInt(); 451 String playerName = (flg & 0x80) == 0 ? null : in.readString(); 452 String playerVersion = (flg & 0x100) == 0 ? null : in.readString(); 453 long[] experimentIds = in.createLongArray(); 454 int videoFramesPlayed = in.readInt(); 455 int videoFramesDropped = in.readInt(); 456 int audioUnderrunCount = in.readInt(); 457 long networkBytesRead = in.readLong(); 458 long localBytesRead = in.readLong(); 459 long networkTransferDurationMillis = in.readLong(); 460 int drmSessionIdLen = in.readInt(); 461 byte[] drmSessionId = new byte[drmSessionIdLen]; 462 in.readByteArray(drmSessionId); 463 Bundle extras = in.readBundle(); 464 465 this.mMediaDurationMillis = mediaDurationMillis; 466 this.mStreamSource = streamSource; 467 this.mStreamType = streamType; 468 this.mPlaybackType = playbackType; 469 this.mDrmType = drmType; 470 this.mContentType = contentType; 471 this.mPlayerName = playerName; 472 this.mPlayerVersion = playerVersion; 473 this.mExperimentIds = experimentIds; 474 AnnotationValidations.validate(NonNull.class, null, mExperimentIds); 475 this.mVideoFramesPlayed = videoFramesPlayed; 476 this.mVideoFramesDropped = videoFramesDropped; 477 this.mAudioUnderrunCount = audioUnderrunCount; 478 this.mNetworkBytesRead = networkBytesRead; 479 this.mLocalBytesRead = localBytesRead; 480 this.mNetworkTransferDurationMillis = networkTransferDurationMillis; 481 this.mDrmSessionId = drmSessionId; 482 this.mMetricsBundle = extras; 483 } 484 485 public static final @NonNull Parcelable.Creator<PlaybackMetrics> CREATOR = 486 new Parcelable.Creator<PlaybackMetrics>() { 487 @Override 488 public PlaybackMetrics[] newArray(int size) { 489 return new PlaybackMetrics[size]; 490 } 491 492 @Override 493 public PlaybackMetrics createFromParcel(@NonNull Parcel in) { 494 return new PlaybackMetrics(in); 495 } 496 }; 497 498 /** 499 * A builder for {@link PlaybackMetrics} 500 */ 501 public static final class Builder { 502 503 private long mMediaDurationMillis = -1; 504 private int mStreamSource = STREAM_SOURCE_UNKNOWN; 505 private int mStreamType = STREAM_TYPE_UNKNOWN; 506 private int mPlaybackType = PLAYBACK_TYPE_UNKNOWN; 507 private int mDrmType = DRM_TYPE_NONE; 508 private int mContentType = CONTENT_TYPE_UNKNOWN; 509 private @Nullable String mPlayerName; 510 private @Nullable String mPlayerVersion; 511 private @NonNull List<Long> mExperimentIds = new ArrayList<>(); 512 private int mVideoFramesPlayed = -1; 513 private int mVideoFramesDropped = -1; 514 private int mAudioUnderrunCount = -1; 515 private long mNetworkBytesRead = -1; 516 private long mLocalBytesRead = -1; 517 private long mNetworkTransferDurationMillis = -1; 518 private byte[] mDrmSessionId = new byte[0]; 519 private Bundle mMetricsBundle = new Bundle(); 520 521 /** 522 * Creates a new Builder. 523 */ Builder()524 public Builder() { 525 } 526 527 /** 528 * Sets the media duration in milliseconds. 529 * @param value the media duration in milliseconds. -1 indicates the value is unknown. 530 * @see #getMediaDurationMillis() 531 */ setMediaDurationMillis(@ntRangefrom = -1) long value)532 public @NonNull Builder setMediaDurationMillis(@IntRange(from = -1) long value) { 533 mMediaDurationMillis = value; 534 return this; 535 } 536 537 /** 538 * Sets the stream source type. 539 */ setStreamSource(@treamSource int value)540 public @NonNull Builder setStreamSource(@StreamSource int value) { 541 mStreamSource = value; 542 return this; 543 } 544 545 /** 546 * Sets the stream type. 547 */ setStreamType(@treamType int value)548 public @NonNull Builder setStreamType(@StreamType int value) { 549 mStreamType = value; 550 return this; 551 } 552 553 /** 554 * Sets the playback type. 555 */ setPlaybackType(@laybackType int value)556 public @NonNull Builder setPlaybackType(@PlaybackType int value) { 557 mPlaybackType = value; 558 return this; 559 } 560 561 /** 562 * Sets the DRM type. 563 */ setDrmType(@rmType int value)564 public @NonNull Builder setDrmType(@DrmType int value) { 565 mDrmType = value; 566 return this; 567 } 568 569 /** 570 * Sets the content type. 571 */ setContentType(@ontentType int value)572 public @NonNull Builder setContentType(@ContentType int value) { 573 mContentType = value; 574 return this; 575 } 576 577 /** 578 * Sets the player name. 579 */ setPlayerName(@onNull String value)580 public @NonNull Builder setPlayerName(@NonNull String value) { 581 mPlayerName = value; 582 return this; 583 } 584 585 /** 586 * Sets the player version. 587 */ setPlayerVersion(@onNull String value)588 public @NonNull Builder setPlayerVersion(@NonNull String value) { 589 mPlayerVersion = value; 590 return this; 591 } 592 593 /** 594 * Adds the experiment ID. 595 */ addExperimentId(long value)596 public @NonNull Builder addExperimentId(long value) { 597 mExperimentIds.add(value); 598 return this; 599 } 600 601 /** 602 * Sets the video frames played. 603 * @param value the video frames played. -1 indicates the value is unknown. 604 */ setVideoFramesPlayed( @ntRangefrom = -1, to = Integer.MAX_VALUE) int value)605 public @NonNull Builder setVideoFramesPlayed( 606 @IntRange(from = -1, to = Integer.MAX_VALUE) int value) { 607 mVideoFramesPlayed = value; 608 return this; 609 } 610 611 /** 612 * Sets the video frames dropped. 613 * @param value the video frames dropped. -1 indicates the value is unknown. 614 */ setVideoFramesDropped( @ntRangefrom = -1, to = Integer.MAX_VALUE) int value)615 public @NonNull Builder setVideoFramesDropped( 616 @IntRange(from = -1, to = Integer.MAX_VALUE) int value) { 617 mVideoFramesDropped = value; 618 return this; 619 } 620 621 /** 622 * Sets the audio underrun count. 623 * @param value the audio underrun count. -1 indicates the value is unknown. 624 */ setAudioUnderrunCount( @ntRangefrom = -1, to = Integer.MAX_VALUE) int value)625 public @NonNull Builder setAudioUnderrunCount( 626 @IntRange(from = -1, to = Integer.MAX_VALUE) int value) { 627 mAudioUnderrunCount = value; 628 return this; 629 } 630 631 /** 632 * Sets the number of network bytes read. 633 * @param value the number of network bytes read. -1 indicates the value is unknown. 634 */ setNetworkBytesRead(@ntRangefrom = -1) long value)635 public @NonNull Builder setNetworkBytesRead(@IntRange(from = -1) long value) { 636 mNetworkBytesRead = value; 637 return this; 638 } 639 640 /** 641 * Sets the number of local bytes read. 642 * @param value the number of local bytes read. -1 indicates the value is unknown. 643 */ setLocalBytesRead(@ntRangefrom = -1) long value)644 public @NonNull Builder setLocalBytesRead(@IntRange(from = -1) long value) { 645 mLocalBytesRead = value; 646 return this; 647 } 648 649 /** 650 * Sets the network transfer duration in milliseconds. 651 * @param value the network transfer duration in milliseconds. 652 * -1 indicates the value is unknown. 653 * @see #getNetworkTransferDurationMillis() 654 */ setNetworkTransferDurationMillis(@ntRangefrom = -1) long value)655 public @NonNull Builder setNetworkTransferDurationMillis(@IntRange(from = -1) long value) { 656 mNetworkTransferDurationMillis = value; 657 return this; 658 } 659 660 /** 661 * Sets DRM session ID. 662 */ setDrmSessionId(@onNull byte[] drmSessionId)663 public @NonNull Builder setDrmSessionId(@NonNull byte[] drmSessionId) { 664 mDrmSessionId = drmSessionId; 665 return this; 666 } 667 668 /** 669 * Sets metrics-related information that is not supported by dedicated 670 * methods. 671 * <p>It is intended to be used for backwards compatibility by the 672 * metrics infrastructure. 673 */ setMetricsBundle(@onNull Bundle metricsBundle)674 public @NonNull Builder setMetricsBundle(@NonNull Bundle metricsBundle) { 675 mMetricsBundle = metricsBundle; 676 return this; 677 } 678 679 /** Builds the instance. This builder should not be touched after calling this! */ build()680 public @NonNull PlaybackMetrics build() { 681 682 PlaybackMetrics o = new PlaybackMetrics( 683 mMediaDurationMillis, 684 mStreamSource, 685 mStreamType, 686 mPlaybackType, 687 mDrmType, 688 mContentType, 689 mPlayerName, 690 mPlayerVersion, 691 idsToLongArray(), 692 mVideoFramesPlayed, 693 mVideoFramesDropped, 694 mAudioUnderrunCount, 695 mNetworkBytesRead, 696 mLocalBytesRead, 697 mNetworkTransferDurationMillis, 698 mDrmSessionId, 699 mMetricsBundle); 700 return o; 701 } 702 idsToLongArray()703 private long[] idsToLongArray() { 704 long[] ids = new long[mExperimentIds.size()]; 705 for (int i = 0; i < mExperimentIds.size(); i++) { 706 ids[i] = mExperimentIds.get(i); 707 } 708 return ids; 709 } 710 } 711 } 712