1 /* 2 * Copyright (C) 2019 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 package com.google.android.exoplayer2.analytics; 17 18 import android.os.SystemClock; 19 import androidx.annotation.IntDef; 20 import androidx.annotation.Nullable; 21 import com.google.android.exoplayer2.C; 22 import com.google.android.exoplayer2.Format; 23 import com.google.android.exoplayer2.analytics.AnalyticsListener.EventTime; 24 import java.lang.annotation.Documented; 25 import java.lang.annotation.ElementType; 26 import java.lang.annotation.Retention; 27 import java.lang.annotation.RetentionPolicy; 28 import java.lang.annotation.Target; 29 import java.util.Collections; 30 import java.util.List; 31 32 /** Statistics about playbacks. */ 33 public final class PlaybackStats { 34 35 /** Stores a playback state with the event time at which it became active. */ 36 public static final class EventTimeAndPlaybackState { 37 /** The event time at which the playback state became active. */ 38 public final EventTime eventTime; 39 /** The playback state that became active. */ 40 public final @PlaybackState int playbackState; 41 42 /** 43 * Creates a new timed playback state event. 44 * 45 * @param eventTime The event time at which the playback state became active. 46 * @param playbackState The playback state that became active. 47 */ EventTimeAndPlaybackState(EventTime eventTime, @PlaybackState int playbackState)48 public EventTimeAndPlaybackState(EventTime eventTime, @PlaybackState int playbackState) { 49 this.eventTime = eventTime; 50 this.playbackState = playbackState; 51 } 52 53 @Override equals(@ullable Object o)54 public boolean equals(@Nullable Object o) { 55 if (this == o) { 56 return true; 57 } 58 if (o == null || getClass() != o.getClass()) { 59 return false; 60 } 61 EventTimeAndPlaybackState that = (EventTimeAndPlaybackState) o; 62 if (playbackState != that.playbackState) { 63 return false; 64 } 65 return eventTime.equals(that.eventTime); 66 } 67 68 @Override hashCode()69 public int hashCode() { 70 int result = eventTime.hashCode(); 71 result = 31 * result + playbackState; 72 return result; 73 } 74 } 75 76 /** 77 * Stores a format with the event time at which it started being used, or {@code null} to indicate 78 * that no format was used. 79 */ 80 public static final class EventTimeAndFormat { 81 /** The event time associated with {@link #format}. */ 82 public final EventTime eventTime; 83 /** The format that started being used, or {@code null} if no format was used. */ 84 @Nullable public final Format format; 85 86 /** 87 * Creates a new timed format event. 88 * 89 * @param eventTime The event time associated with {@code format}. 90 * @param format The format that started being used, or {@code null} if no format was used. 91 */ EventTimeAndFormat(EventTime eventTime, @Nullable Format format)92 public EventTimeAndFormat(EventTime eventTime, @Nullable Format format) { 93 this.eventTime = eventTime; 94 this.format = format; 95 } 96 97 @Override equals(@ullable Object o)98 public boolean equals(@Nullable Object o) { 99 if (this == o) { 100 return true; 101 } 102 if (o == null || getClass() != o.getClass()) { 103 return false; 104 } 105 EventTimeAndFormat that = (EventTimeAndFormat) o; 106 if (!eventTime.equals(that.eventTime)) { 107 return false; 108 } 109 return format != null ? format.equals(that.format) : that.format == null; 110 } 111 112 @Override hashCode()113 public int hashCode() { 114 int result = eventTime.hashCode(); 115 result = 31 * result + (format != null ? format.hashCode() : 0); 116 return result; 117 } 118 } 119 120 /** Stores an exception with the event time at which it occurred. */ 121 public static final class EventTimeAndException { 122 /** The event time at which the exception occurred. */ 123 public final EventTime eventTime; 124 /** The exception that was thrown. */ 125 public final Exception exception; 126 127 /** 128 * Creates a new timed exception event. 129 * 130 * @param eventTime The event time at which the exception occurred. 131 * @param exception The exception that was thrown. 132 */ EventTimeAndException(EventTime eventTime, Exception exception)133 public EventTimeAndException(EventTime eventTime, Exception exception) { 134 this.eventTime = eventTime; 135 this.exception = exception; 136 } 137 138 @Override equals(@ullable Object o)139 public boolean equals(@Nullable Object o) { 140 if (this == o) { 141 return true; 142 } 143 if (o == null || getClass() != o.getClass()) { 144 return false; 145 } 146 EventTimeAndException that = (EventTimeAndException) o; 147 if (!eventTime.equals(that.eventTime)) { 148 return false; 149 } 150 return exception.equals(that.exception); 151 } 152 153 @Override hashCode()154 public int hashCode() { 155 int result = eventTime.hashCode(); 156 result = 31 * result + exception.hashCode(); 157 return result; 158 } 159 } 160 161 /** 162 * State of a playback. One of {@link #PLAYBACK_STATE_NOT_STARTED}, {@link 163 * #PLAYBACK_STATE_JOINING_FOREGROUND}, {@link #PLAYBACK_STATE_JOINING_BACKGROUND}, {@link 164 * #PLAYBACK_STATE_PLAYING}, {@link #PLAYBACK_STATE_PAUSED}, {@link #PLAYBACK_STATE_SEEKING}, 165 * {@link #PLAYBACK_STATE_BUFFERING}, {@link #PLAYBACK_STATE_PAUSED_BUFFERING}, {@link 166 * #PLAYBACK_STATE_SUPPRESSED}, {@link #PLAYBACK_STATE_SUPPRESSED_BUFFERING}, {@link 167 * #PLAYBACK_STATE_ENDED}, {@link #PLAYBACK_STATE_STOPPED}, {@link #PLAYBACK_STATE_FAILED}, {@link 168 * #PLAYBACK_STATE_INTERRUPTED_BY_AD} or {@link #PLAYBACK_STATE_ABANDONED}. 169 */ 170 @Documented 171 @Retention(RetentionPolicy.SOURCE) 172 @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) 173 @IntDef({ 174 PLAYBACK_STATE_NOT_STARTED, 175 PLAYBACK_STATE_JOINING_BACKGROUND, 176 PLAYBACK_STATE_JOINING_FOREGROUND, 177 PLAYBACK_STATE_PLAYING, 178 PLAYBACK_STATE_PAUSED, 179 PLAYBACK_STATE_SEEKING, 180 PLAYBACK_STATE_BUFFERING, 181 PLAYBACK_STATE_PAUSED_BUFFERING, 182 PLAYBACK_STATE_SUPPRESSED, 183 PLAYBACK_STATE_SUPPRESSED_BUFFERING, 184 PLAYBACK_STATE_ENDED, 185 PLAYBACK_STATE_STOPPED, 186 PLAYBACK_STATE_FAILED, 187 PLAYBACK_STATE_INTERRUPTED_BY_AD, 188 PLAYBACK_STATE_ABANDONED 189 }) 190 @interface PlaybackState {} 191 /** Playback has not started (initial state). */ 192 public static final int PLAYBACK_STATE_NOT_STARTED = 0; 193 /** Playback is buffering in the background for initial playback start. */ 194 public static final int PLAYBACK_STATE_JOINING_BACKGROUND = 1; 195 /** Playback is buffering in the foreground for initial playback start. */ 196 public static final int PLAYBACK_STATE_JOINING_FOREGROUND = 2; 197 /** Playback is actively playing. */ 198 public static final int PLAYBACK_STATE_PLAYING = 3; 199 /** Playback is paused but ready to play. */ 200 public static final int PLAYBACK_STATE_PAUSED = 4; 201 /** Playback is handling a seek. */ 202 public static final int PLAYBACK_STATE_SEEKING = 5; 203 /** Playback is buffering to resume active playback. */ 204 public static final int PLAYBACK_STATE_BUFFERING = 6; 205 /** Playback is buffering while paused. */ 206 public static final int PLAYBACK_STATE_PAUSED_BUFFERING = 7; 207 /** Playback is suppressed (e.g. due to audio focus loss). */ 208 public static final int PLAYBACK_STATE_SUPPRESSED = 9; 209 /** Playback is suppressed (e.g. due to audio focus loss) while buffering to resume a playback. */ 210 public static final int PLAYBACK_STATE_SUPPRESSED_BUFFERING = 10; 211 /** Playback has reached the end of the media. */ 212 public static final int PLAYBACK_STATE_ENDED = 11; 213 /** Playback is stopped and can be restarted. */ 214 public static final int PLAYBACK_STATE_STOPPED = 12; 215 /** Playback is stopped due a fatal error and can be retried. */ 216 public static final int PLAYBACK_STATE_FAILED = 13; 217 /** Playback is interrupted by an ad. */ 218 public static final int PLAYBACK_STATE_INTERRUPTED_BY_AD = 14; 219 /** Playback is abandoned before reaching the end of the media. */ 220 public static final int PLAYBACK_STATE_ABANDONED = 15; 221 /** Total number of playback states. */ 222 /* package */ static final int PLAYBACK_STATE_COUNT = 16; 223 224 /** Empty playback stats. */ 225 public static final PlaybackStats EMPTY = merge(/* nothing */ ); 226 227 /** 228 * Returns the combined {@link PlaybackStats} for all input {@link PlaybackStats}. 229 * 230 * <p>Note that the full history of events is not kept as the history only makes sense in the 231 * context of a single playback. 232 * 233 * @param playbackStats Array of {@link PlaybackStats} to combine. 234 * @return The combined {@link PlaybackStats}. 235 */ merge(PlaybackStats... playbackStats)236 public static PlaybackStats merge(PlaybackStats... playbackStats) { 237 int playbackCount = 0; 238 long[] playbackStateDurationsMs = new long[PLAYBACK_STATE_COUNT]; 239 long firstReportedTimeMs = C.TIME_UNSET; 240 int foregroundPlaybackCount = 0; 241 int abandonedBeforeReadyCount = 0; 242 int endedCount = 0; 243 int backgroundJoiningCount = 0; 244 long totalValidJoinTimeMs = C.TIME_UNSET; 245 int validJoinTimeCount = 0; 246 int totalPauseCount = 0; 247 int totalPauseBufferCount = 0; 248 int totalSeekCount = 0; 249 int totalRebufferCount = 0; 250 long maxRebufferTimeMs = C.TIME_UNSET; 251 int adPlaybackCount = 0; 252 long totalVideoFormatHeightTimeMs = 0; 253 long totalVideoFormatHeightTimeProduct = 0; 254 long totalVideoFormatBitrateTimeMs = 0; 255 long totalVideoFormatBitrateTimeProduct = 0; 256 long totalAudioFormatTimeMs = 0; 257 long totalAudioFormatBitrateTimeProduct = 0; 258 int initialVideoFormatHeightCount = 0; 259 int initialVideoFormatBitrateCount = 0; 260 int totalInitialVideoFormatHeight = C.LENGTH_UNSET; 261 long totalInitialVideoFormatBitrate = C.LENGTH_UNSET; 262 int initialAudioFormatBitrateCount = 0; 263 long totalInitialAudioFormatBitrate = C.LENGTH_UNSET; 264 long totalBandwidthTimeMs = 0; 265 long totalBandwidthBytes = 0; 266 long totalDroppedFrames = 0; 267 long totalAudioUnderruns = 0; 268 int fatalErrorPlaybackCount = 0; 269 int fatalErrorCount = 0; 270 int nonFatalErrorCount = 0; 271 for (PlaybackStats stats : playbackStats) { 272 playbackCount += stats.playbackCount; 273 for (int i = 0; i < PLAYBACK_STATE_COUNT; i++) { 274 playbackStateDurationsMs[i] += stats.playbackStateDurationsMs[i]; 275 } 276 if (firstReportedTimeMs == C.TIME_UNSET) { 277 firstReportedTimeMs = stats.firstReportedTimeMs; 278 } else if (stats.firstReportedTimeMs != C.TIME_UNSET) { 279 firstReportedTimeMs = Math.min(firstReportedTimeMs, stats.firstReportedTimeMs); 280 } 281 foregroundPlaybackCount += stats.foregroundPlaybackCount; 282 abandonedBeforeReadyCount += stats.abandonedBeforeReadyCount; 283 endedCount += stats.endedCount; 284 backgroundJoiningCount += stats.backgroundJoiningCount; 285 if (totalValidJoinTimeMs == C.TIME_UNSET) { 286 totalValidJoinTimeMs = stats.totalValidJoinTimeMs; 287 } else if (stats.totalValidJoinTimeMs != C.TIME_UNSET) { 288 totalValidJoinTimeMs += stats.totalValidJoinTimeMs; 289 } 290 validJoinTimeCount += stats.validJoinTimeCount; 291 totalPauseCount += stats.totalPauseCount; 292 totalPauseBufferCount += stats.totalPauseBufferCount; 293 totalSeekCount += stats.totalSeekCount; 294 totalRebufferCount += stats.totalRebufferCount; 295 if (maxRebufferTimeMs == C.TIME_UNSET) { 296 maxRebufferTimeMs = stats.maxRebufferTimeMs; 297 } else if (stats.maxRebufferTimeMs != C.TIME_UNSET) { 298 maxRebufferTimeMs = Math.max(maxRebufferTimeMs, stats.maxRebufferTimeMs); 299 } 300 adPlaybackCount += stats.adPlaybackCount; 301 totalVideoFormatHeightTimeMs += stats.totalVideoFormatHeightTimeMs; 302 totalVideoFormatHeightTimeProduct += stats.totalVideoFormatHeightTimeProduct; 303 totalVideoFormatBitrateTimeMs += stats.totalVideoFormatBitrateTimeMs; 304 totalVideoFormatBitrateTimeProduct += stats.totalVideoFormatBitrateTimeProduct; 305 totalAudioFormatTimeMs += stats.totalAudioFormatTimeMs; 306 totalAudioFormatBitrateTimeProduct += stats.totalAudioFormatBitrateTimeProduct; 307 initialVideoFormatHeightCount += stats.initialVideoFormatHeightCount; 308 initialVideoFormatBitrateCount += stats.initialVideoFormatBitrateCount; 309 if (totalInitialVideoFormatHeight == C.LENGTH_UNSET) { 310 totalInitialVideoFormatHeight = stats.totalInitialVideoFormatHeight; 311 } else if (stats.totalInitialVideoFormatHeight != C.LENGTH_UNSET) { 312 totalInitialVideoFormatHeight += stats.totalInitialVideoFormatHeight; 313 } 314 if (totalInitialVideoFormatBitrate == C.LENGTH_UNSET) { 315 totalInitialVideoFormatBitrate = stats.totalInitialVideoFormatBitrate; 316 } else if (stats.totalInitialVideoFormatBitrate != C.LENGTH_UNSET) { 317 totalInitialVideoFormatBitrate += stats.totalInitialVideoFormatBitrate; 318 } 319 initialAudioFormatBitrateCount += stats.initialAudioFormatBitrateCount; 320 if (totalInitialAudioFormatBitrate == C.LENGTH_UNSET) { 321 totalInitialAudioFormatBitrate = stats.totalInitialAudioFormatBitrate; 322 } else if (stats.totalInitialAudioFormatBitrate != C.LENGTH_UNSET) { 323 totalInitialAudioFormatBitrate += stats.totalInitialAudioFormatBitrate; 324 } 325 totalBandwidthTimeMs += stats.totalBandwidthTimeMs; 326 totalBandwidthBytes += stats.totalBandwidthBytes; 327 totalDroppedFrames += stats.totalDroppedFrames; 328 totalAudioUnderruns += stats.totalAudioUnderruns; 329 fatalErrorPlaybackCount += stats.fatalErrorPlaybackCount; 330 fatalErrorCount += stats.fatalErrorCount; 331 nonFatalErrorCount += stats.nonFatalErrorCount; 332 } 333 return new PlaybackStats( 334 playbackCount, 335 playbackStateDurationsMs, 336 /* playbackStateHistory */ Collections.emptyList(), 337 /* mediaTimeHistory= */ Collections.emptyList(), 338 firstReportedTimeMs, 339 foregroundPlaybackCount, 340 abandonedBeforeReadyCount, 341 endedCount, 342 backgroundJoiningCount, 343 totalValidJoinTimeMs, 344 validJoinTimeCount, 345 totalPauseCount, 346 totalPauseBufferCount, 347 totalSeekCount, 348 totalRebufferCount, 349 maxRebufferTimeMs, 350 adPlaybackCount, 351 /* videoFormatHistory= */ Collections.emptyList(), 352 /* audioFormatHistory= */ Collections.emptyList(), 353 totalVideoFormatHeightTimeMs, 354 totalVideoFormatHeightTimeProduct, 355 totalVideoFormatBitrateTimeMs, 356 totalVideoFormatBitrateTimeProduct, 357 totalAudioFormatTimeMs, 358 totalAudioFormatBitrateTimeProduct, 359 initialVideoFormatHeightCount, 360 initialVideoFormatBitrateCount, 361 totalInitialVideoFormatHeight, 362 totalInitialVideoFormatBitrate, 363 initialAudioFormatBitrateCount, 364 totalInitialAudioFormatBitrate, 365 totalBandwidthTimeMs, 366 totalBandwidthBytes, 367 totalDroppedFrames, 368 totalAudioUnderruns, 369 fatalErrorPlaybackCount, 370 fatalErrorCount, 371 nonFatalErrorCount, 372 /* fatalErrorHistory= */ Collections.emptyList(), 373 /* nonFatalErrorHistory= */ Collections.emptyList()); 374 } 375 376 /** The number of individual playbacks for which these stats were collected. */ 377 public final int playbackCount; 378 379 // Playback state stats. 380 381 /** 382 * The playback state history as {@link EventTimeAndPlaybackState EventTimeAndPlaybackStates} 383 * ordered by {@code EventTime.realTimeMs}. 384 */ 385 public final List<EventTimeAndPlaybackState> playbackStateHistory; 386 /** 387 * The media time history as an ordered list of long[2] arrays with [0] being the realtime as 388 * returned by {@code SystemClock.elapsedRealtime()} and [1] being the media time at this 389 * realtime, in milliseconds. 390 */ 391 public final List<long[]> mediaTimeHistory; 392 /** 393 * The elapsed real-time as returned by {@code SystemClock.elapsedRealtime()} of the first 394 * reported playback event, or {@link C#TIME_UNSET} if no event has been reported. 395 */ 396 public final long firstReportedTimeMs; 397 /** The number of playbacks which were the active foreground playback at some point. */ 398 public final int foregroundPlaybackCount; 399 /** The number of playbacks which were abandoned before they were ready to play. */ 400 public final int abandonedBeforeReadyCount; 401 /** The number of playbacks which reached the ended state at least once. */ 402 public final int endedCount; 403 /** The number of playbacks which were pre-buffered in the background. */ 404 public final int backgroundJoiningCount; 405 /** 406 * The total time spent joining the playback, in milliseconds, or {@link C#TIME_UNSET} if no valid 407 * join time could be determined. 408 * 409 * <p>Note that this does not include background joining time. A join time may be invalid if the 410 * playback never reached {@link #PLAYBACK_STATE_PLAYING} or {@link #PLAYBACK_STATE_PAUSED}, or 411 * joining was interrupted by a seek, stop, or error state. 412 */ 413 public final long totalValidJoinTimeMs; 414 /** 415 * The number of playbacks with a valid join time as documented in {@link #totalValidJoinTimeMs}. 416 */ 417 public final int validJoinTimeCount; 418 /** The total number of times a playback has been paused. */ 419 public final int totalPauseCount; 420 /** The total number of times a playback has been paused while rebuffering. */ 421 public final int totalPauseBufferCount; 422 /** 423 * The total number of times a seek occurred. This includes seeks happening before playback 424 * resumed after another seek. 425 */ 426 public final int totalSeekCount; 427 /** 428 * The total number of times a rebuffer occurred. This excludes initial joining and buffering 429 * after seek. 430 */ 431 public final int totalRebufferCount; 432 /** 433 * The maximum time spent during a single rebuffer, in milliseconds, or {@link C#TIME_UNSET} if no 434 * rebuffer occurred. 435 */ 436 public final long maxRebufferTimeMs; 437 /** The number of ad playbacks. */ 438 public final int adPlaybackCount; 439 440 // Format stats. 441 442 /** 443 * The video format history as {@link EventTimeAndFormat EventTimeAndFormats} ordered by {@code 444 * EventTime.realTimeMs}. The {@link Format} may be null if no video format was used. 445 */ 446 public final List<EventTimeAndFormat> videoFormatHistory; 447 /** 448 * The audio format history as {@link EventTimeAndFormat EventTimeAndFormats} ordered by {@code 449 * EventTime.realTimeMs}. The {@link Format} may be null if no audio format was used. 450 */ 451 public final List<EventTimeAndFormat> audioFormatHistory; 452 /** The total media time for which video format height data is available, in milliseconds. */ 453 public final long totalVideoFormatHeightTimeMs; 454 /** 455 * The accumulated sum of all video format heights, in pixels, times the time the format was used 456 * for playback, in milliseconds. 457 */ 458 public final long totalVideoFormatHeightTimeProduct; 459 /** The total media time for which video format bitrate data is available, in milliseconds. */ 460 public final long totalVideoFormatBitrateTimeMs; 461 /** 462 * The accumulated sum of all video format bitrates, in bits per second, times the time the format 463 * was used for playback, in milliseconds. 464 */ 465 public final long totalVideoFormatBitrateTimeProduct; 466 /** The total media time for which audio format data is available, in milliseconds. */ 467 public final long totalAudioFormatTimeMs; 468 /** 469 * The accumulated sum of all audio format bitrates, in bits per second, times the time the format 470 * was used for playback, in milliseconds. 471 */ 472 public final long totalAudioFormatBitrateTimeProduct; 473 /** The number of playbacks with initial video format height data. */ 474 public final int initialVideoFormatHeightCount; 475 /** The number of playbacks with initial video format bitrate data. */ 476 public final int initialVideoFormatBitrateCount; 477 /** 478 * The total initial video format height for all playbacks, in pixels, or {@link C#LENGTH_UNSET} 479 * if no initial video format data is available. 480 */ 481 public final int totalInitialVideoFormatHeight; 482 /** 483 * The total initial video format bitrate for all playbacks, in bits per second, or {@link 484 * C#LENGTH_UNSET} if no initial video format data is available. 485 */ 486 public final long totalInitialVideoFormatBitrate; 487 /** The number of playbacks with initial audio format bitrate data. */ 488 public final int initialAudioFormatBitrateCount; 489 /** 490 * The total initial audio format bitrate for all playbacks, in bits per second, or {@link 491 * C#LENGTH_UNSET} if no initial audio format data is available. 492 */ 493 public final long totalInitialAudioFormatBitrate; 494 495 // Bandwidth stats. 496 497 /** The total time for which bandwidth measurement data is available, in milliseconds. */ 498 public final long totalBandwidthTimeMs; 499 /** The total bytes transferred during {@link #totalBandwidthTimeMs}. */ 500 public final long totalBandwidthBytes; 501 502 // Renderer quality stats. 503 504 /** The total number of dropped video frames. */ 505 public final long totalDroppedFrames; 506 /** The total number of audio underruns. */ 507 public final long totalAudioUnderruns; 508 509 // Error stats. 510 511 /** 512 * The total number of playback with at least one fatal error. Errors are fatal if playback 513 * stopped due to this error. 514 */ 515 public final int fatalErrorPlaybackCount; 516 /** The total number of fatal errors. Errors are fatal if playback stopped due to this error. */ 517 public final int fatalErrorCount; 518 /** 519 * The total number of non-fatal errors. Error are non-fatal if playback can recover from the 520 * error without stopping. 521 */ 522 public final int nonFatalErrorCount; 523 /** 524 * The history of fatal errors as {@link EventTimeAndException EventTimeAndExceptions} ordered by 525 * {@code EventTime.realTimeMs}. Errors are fatal if playback stopped due to this error. 526 */ 527 public final List<EventTimeAndException> fatalErrorHistory; 528 /** 529 * The history of non-fatal errors as {@link EventTimeAndException EventTimeAndExceptions} ordered 530 * by {@code EventTime.realTimeMs}. Errors are non-fatal if playback can recover from the error 531 * without stopping. 532 */ 533 public final List<EventTimeAndException> nonFatalErrorHistory; 534 535 private final long[] playbackStateDurationsMs; 536 PlaybackStats( int playbackCount, long[] playbackStateDurationsMs, List<EventTimeAndPlaybackState> playbackStateHistory, List<long[]> mediaTimeHistory, long firstReportedTimeMs, int foregroundPlaybackCount, int abandonedBeforeReadyCount, int endedCount, int backgroundJoiningCount, long totalValidJoinTimeMs, int validJoinTimeCount, int totalPauseCount, int totalPauseBufferCount, int totalSeekCount, int totalRebufferCount, long maxRebufferTimeMs, int adPlaybackCount, List<EventTimeAndFormat> videoFormatHistory, List<EventTimeAndFormat> audioFormatHistory, long totalVideoFormatHeightTimeMs, long totalVideoFormatHeightTimeProduct, long totalVideoFormatBitrateTimeMs, long totalVideoFormatBitrateTimeProduct, long totalAudioFormatTimeMs, long totalAudioFormatBitrateTimeProduct, int initialVideoFormatHeightCount, int initialVideoFormatBitrateCount, int totalInitialVideoFormatHeight, long totalInitialVideoFormatBitrate, int initialAudioFormatBitrateCount, long totalInitialAudioFormatBitrate, long totalBandwidthTimeMs, long totalBandwidthBytes, long totalDroppedFrames, long totalAudioUnderruns, int fatalErrorPlaybackCount, int fatalErrorCount, int nonFatalErrorCount, List<EventTimeAndException> fatalErrorHistory, List<EventTimeAndException> nonFatalErrorHistory)537 /* package */ PlaybackStats( 538 int playbackCount, 539 long[] playbackStateDurationsMs, 540 List<EventTimeAndPlaybackState> playbackStateHistory, 541 List<long[]> mediaTimeHistory, 542 long firstReportedTimeMs, 543 int foregroundPlaybackCount, 544 int abandonedBeforeReadyCount, 545 int endedCount, 546 int backgroundJoiningCount, 547 long totalValidJoinTimeMs, 548 int validJoinTimeCount, 549 int totalPauseCount, 550 int totalPauseBufferCount, 551 int totalSeekCount, 552 int totalRebufferCount, 553 long maxRebufferTimeMs, 554 int adPlaybackCount, 555 List<EventTimeAndFormat> videoFormatHistory, 556 List<EventTimeAndFormat> audioFormatHistory, 557 long totalVideoFormatHeightTimeMs, 558 long totalVideoFormatHeightTimeProduct, 559 long totalVideoFormatBitrateTimeMs, 560 long totalVideoFormatBitrateTimeProduct, 561 long totalAudioFormatTimeMs, 562 long totalAudioFormatBitrateTimeProduct, 563 int initialVideoFormatHeightCount, 564 int initialVideoFormatBitrateCount, 565 int totalInitialVideoFormatHeight, 566 long totalInitialVideoFormatBitrate, 567 int initialAudioFormatBitrateCount, 568 long totalInitialAudioFormatBitrate, 569 long totalBandwidthTimeMs, 570 long totalBandwidthBytes, 571 long totalDroppedFrames, 572 long totalAudioUnderruns, 573 int fatalErrorPlaybackCount, 574 int fatalErrorCount, 575 int nonFatalErrorCount, 576 List<EventTimeAndException> fatalErrorHistory, 577 List<EventTimeAndException> nonFatalErrorHistory) { 578 this.playbackCount = playbackCount; 579 this.playbackStateDurationsMs = playbackStateDurationsMs; 580 this.playbackStateHistory = Collections.unmodifiableList(playbackStateHistory); 581 this.mediaTimeHistory = Collections.unmodifiableList(mediaTimeHistory); 582 this.firstReportedTimeMs = firstReportedTimeMs; 583 this.foregroundPlaybackCount = foregroundPlaybackCount; 584 this.abandonedBeforeReadyCount = abandonedBeforeReadyCount; 585 this.endedCount = endedCount; 586 this.backgroundJoiningCount = backgroundJoiningCount; 587 this.totalValidJoinTimeMs = totalValidJoinTimeMs; 588 this.validJoinTimeCount = validJoinTimeCount; 589 this.totalPauseCount = totalPauseCount; 590 this.totalPauseBufferCount = totalPauseBufferCount; 591 this.totalSeekCount = totalSeekCount; 592 this.totalRebufferCount = totalRebufferCount; 593 this.maxRebufferTimeMs = maxRebufferTimeMs; 594 this.adPlaybackCount = adPlaybackCount; 595 this.videoFormatHistory = Collections.unmodifiableList(videoFormatHistory); 596 this.audioFormatHistory = Collections.unmodifiableList(audioFormatHistory); 597 this.totalVideoFormatHeightTimeMs = totalVideoFormatHeightTimeMs; 598 this.totalVideoFormatHeightTimeProduct = totalVideoFormatHeightTimeProduct; 599 this.totalVideoFormatBitrateTimeMs = totalVideoFormatBitrateTimeMs; 600 this.totalVideoFormatBitrateTimeProduct = totalVideoFormatBitrateTimeProduct; 601 this.totalAudioFormatTimeMs = totalAudioFormatTimeMs; 602 this.totalAudioFormatBitrateTimeProduct = totalAudioFormatBitrateTimeProduct; 603 this.initialVideoFormatHeightCount = initialVideoFormatHeightCount; 604 this.initialVideoFormatBitrateCount = initialVideoFormatBitrateCount; 605 this.totalInitialVideoFormatHeight = totalInitialVideoFormatHeight; 606 this.totalInitialVideoFormatBitrate = totalInitialVideoFormatBitrate; 607 this.initialAudioFormatBitrateCount = initialAudioFormatBitrateCount; 608 this.totalInitialAudioFormatBitrate = totalInitialAudioFormatBitrate; 609 this.totalBandwidthTimeMs = totalBandwidthTimeMs; 610 this.totalBandwidthBytes = totalBandwidthBytes; 611 this.totalDroppedFrames = totalDroppedFrames; 612 this.totalAudioUnderruns = totalAudioUnderruns; 613 this.fatalErrorPlaybackCount = fatalErrorPlaybackCount; 614 this.fatalErrorCount = fatalErrorCount; 615 this.nonFatalErrorCount = nonFatalErrorCount; 616 this.fatalErrorHistory = Collections.unmodifiableList(fatalErrorHistory); 617 this.nonFatalErrorHistory = Collections.unmodifiableList(nonFatalErrorHistory); 618 } 619 620 /** 621 * Returns the total time spent in a given {@link PlaybackState}, in milliseconds. 622 * 623 * @param playbackState A {@link PlaybackState}. 624 * @return Total spent in the given playback state, in milliseconds 625 */ getPlaybackStateDurationMs(@laybackState int playbackState)626 public long getPlaybackStateDurationMs(@PlaybackState int playbackState) { 627 return playbackStateDurationsMs[playbackState]; 628 } 629 630 /** 631 * Returns the {@link PlaybackState} at the given time. 632 * 633 * @param realtimeMs The time as returned by {@link SystemClock#elapsedRealtime()}. 634 * @return The {@link PlaybackState} at that time, or {@link #PLAYBACK_STATE_NOT_STARTED} if the 635 * given time is before the first known playback state in the history. 636 */ getPlaybackStateAtTime(long realtimeMs)637 public @PlaybackState int getPlaybackStateAtTime(long realtimeMs) { 638 @PlaybackState int state = PLAYBACK_STATE_NOT_STARTED; 639 for (EventTimeAndPlaybackState timeAndState : playbackStateHistory) { 640 if (timeAndState.eventTime.realtimeMs > realtimeMs) { 641 break; 642 } 643 state = timeAndState.playbackState; 644 } 645 return state; 646 } 647 648 /** 649 * Returns the estimated media time at the given realtime, in milliseconds, or {@link 650 * C#TIME_UNSET} if the media time history is unknown. 651 * 652 * @param realtimeMs The realtime as returned by {@link SystemClock#elapsedRealtime()}. 653 * @return The estimated media time in milliseconds at this realtime, {@link C#TIME_UNSET} if no 654 * estimate can be given. 655 */ getMediaTimeMsAtRealtimeMs(long realtimeMs)656 public long getMediaTimeMsAtRealtimeMs(long realtimeMs) { 657 if (mediaTimeHistory.isEmpty()) { 658 return C.TIME_UNSET; 659 } 660 int nextIndex = 0; 661 while (nextIndex < mediaTimeHistory.size() 662 && mediaTimeHistory.get(nextIndex)[0] <= realtimeMs) { 663 nextIndex++; 664 } 665 if (nextIndex == 0) { 666 return mediaTimeHistory.get(0)[1]; 667 } 668 if (nextIndex == mediaTimeHistory.size()) { 669 return mediaTimeHistory.get(mediaTimeHistory.size() - 1)[1]; 670 } 671 long prevRealtimeMs = mediaTimeHistory.get(nextIndex - 1)[0]; 672 long prevMediaTimeMs = mediaTimeHistory.get(nextIndex - 1)[1]; 673 long nextRealtimeMs = mediaTimeHistory.get(nextIndex)[0]; 674 long nextMediaTimeMs = mediaTimeHistory.get(nextIndex)[1]; 675 long realtimeDurationMs = nextRealtimeMs - prevRealtimeMs; 676 if (realtimeDurationMs == 0) { 677 return prevMediaTimeMs; 678 } 679 float fraction = (float) (realtimeMs - prevRealtimeMs) / realtimeDurationMs; 680 return prevMediaTimeMs + (long) ((nextMediaTimeMs - prevMediaTimeMs) * fraction); 681 } 682 683 /** 684 * Returns the mean time spent joining the playback, in milliseconds, or {@link C#TIME_UNSET} if 685 * no valid join time is available. Only includes playbacks with valid join times as documented in 686 * {@link #totalValidJoinTimeMs}. 687 */ getMeanJoinTimeMs()688 public long getMeanJoinTimeMs() { 689 return validJoinTimeCount == 0 ? C.TIME_UNSET : totalValidJoinTimeMs / validJoinTimeCount; 690 } 691 692 /** 693 * Returns the total time spent joining the playback in foreground, in milliseconds. This does 694 * include invalid join times where the playback never reached {@link #PLAYBACK_STATE_PLAYING} or 695 * {@link #PLAYBACK_STATE_PAUSED}, or joining was interrupted by a seek, stop, or error state. 696 */ getTotalJoinTimeMs()697 public long getTotalJoinTimeMs() { 698 return getPlaybackStateDurationMs(PLAYBACK_STATE_JOINING_FOREGROUND); 699 } 700 701 /** Returns the total time spent actively playing, in milliseconds. */ getTotalPlayTimeMs()702 public long getTotalPlayTimeMs() { 703 return getPlaybackStateDurationMs(PLAYBACK_STATE_PLAYING); 704 } 705 706 /** 707 * Returns the mean time spent actively playing per foreground playback, in milliseconds, or 708 * {@link C#TIME_UNSET} if no playback has been in foreground. 709 */ getMeanPlayTimeMs()710 public long getMeanPlayTimeMs() { 711 return foregroundPlaybackCount == 0 712 ? C.TIME_UNSET 713 : getTotalPlayTimeMs() / foregroundPlaybackCount; 714 } 715 716 /** Returns the total time spent in a paused state, in milliseconds. */ getTotalPausedTimeMs()717 public long getTotalPausedTimeMs() { 718 return getPlaybackStateDurationMs(PLAYBACK_STATE_PAUSED) 719 + getPlaybackStateDurationMs(PLAYBACK_STATE_PAUSED_BUFFERING); 720 } 721 722 /** 723 * Returns the mean time spent in a paused state per foreground playback, in milliseconds, or 724 * {@link C#TIME_UNSET} if no playback has been in foreground. 725 */ getMeanPausedTimeMs()726 public long getMeanPausedTimeMs() { 727 return foregroundPlaybackCount == 0 728 ? C.TIME_UNSET 729 : getTotalPausedTimeMs() / foregroundPlaybackCount; 730 } 731 732 /** 733 * Returns the total time spent rebuffering, in milliseconds. This excludes initial join times, 734 * buffer times after a seek and buffering while paused. 735 */ getTotalRebufferTimeMs()736 public long getTotalRebufferTimeMs() { 737 return getPlaybackStateDurationMs(PLAYBACK_STATE_BUFFERING); 738 } 739 740 /** 741 * Returns the mean time spent rebuffering per foreground playback, in milliseconds, or {@link 742 * C#TIME_UNSET} if no playback has been in foreground. This excludes initial join times, buffer 743 * times after a seek and buffering while paused. 744 */ getMeanRebufferTimeMs()745 public long getMeanRebufferTimeMs() { 746 return foregroundPlaybackCount == 0 747 ? C.TIME_UNSET 748 : getTotalRebufferTimeMs() / foregroundPlaybackCount; 749 } 750 751 /** 752 * Returns the mean time spent during a single rebuffer, in milliseconds, or {@link C#TIME_UNSET} 753 * if no rebuffer was recorded. This excludes initial join times and buffer times after a seek. 754 */ getMeanSingleRebufferTimeMs()755 public long getMeanSingleRebufferTimeMs() { 756 return totalRebufferCount == 0 757 ? C.TIME_UNSET 758 : (getPlaybackStateDurationMs(PLAYBACK_STATE_BUFFERING) 759 + getPlaybackStateDurationMs(PLAYBACK_STATE_PAUSED_BUFFERING)) 760 / totalRebufferCount; 761 } 762 763 /** 764 * Returns the total time spent from the start of a seek until playback is ready again, in 765 * milliseconds. 766 */ getTotalSeekTimeMs()767 public long getTotalSeekTimeMs() { 768 return getPlaybackStateDurationMs(PLAYBACK_STATE_SEEKING); 769 } 770 771 /** 772 * Returns the mean time spent per foreground playback from the start of a seek until playback is 773 * ready again, in milliseconds, or {@link C#TIME_UNSET} if no playback has been in foreground. 774 */ getMeanSeekTimeMs()775 public long getMeanSeekTimeMs() { 776 return foregroundPlaybackCount == 0 777 ? C.TIME_UNSET 778 : getTotalSeekTimeMs() / foregroundPlaybackCount; 779 } 780 781 /** 782 * Returns the mean time spent from the start of a single seek until playback is ready again, in 783 * milliseconds, or {@link C#TIME_UNSET} if no seek occurred. 784 */ getMeanSingleSeekTimeMs()785 public long getMeanSingleSeekTimeMs() { 786 return totalSeekCount == 0 ? C.TIME_UNSET : getTotalSeekTimeMs() / totalSeekCount; 787 } 788 789 /** 790 * Returns the total time spent actively waiting for playback, in milliseconds. This includes all 791 * join times, rebuffer times and seek times, but excludes times without user intention to play, 792 * e.g. all paused states. 793 */ getTotalWaitTimeMs()794 public long getTotalWaitTimeMs() { 795 return getPlaybackStateDurationMs(PLAYBACK_STATE_JOINING_FOREGROUND) 796 + getPlaybackStateDurationMs(PLAYBACK_STATE_BUFFERING) 797 + getPlaybackStateDurationMs(PLAYBACK_STATE_SEEKING); 798 } 799 800 /** 801 * Returns the mean time spent actively waiting for playback per foreground playback, in 802 * milliseconds, or {@link C#TIME_UNSET} if no playback has been in foreground. This includes all 803 * join times, rebuffer times and seek times, but excludes times without user intention to play, 804 * e.g. all paused states. 805 */ getMeanWaitTimeMs()806 public long getMeanWaitTimeMs() { 807 return foregroundPlaybackCount == 0 808 ? C.TIME_UNSET 809 : getTotalWaitTimeMs() / foregroundPlaybackCount; 810 } 811 812 /** Returns the total time spent playing or actively waiting for playback, in milliseconds. */ getTotalPlayAndWaitTimeMs()813 public long getTotalPlayAndWaitTimeMs() { 814 return getTotalPlayTimeMs() + getTotalWaitTimeMs(); 815 } 816 817 /** 818 * Returns the mean time spent playing or actively waiting for playback per foreground playback, 819 * in milliseconds, or {@link C#TIME_UNSET} if no playback has been in foreground. 820 */ getMeanPlayAndWaitTimeMs()821 public long getMeanPlayAndWaitTimeMs() { 822 return foregroundPlaybackCount == 0 823 ? C.TIME_UNSET 824 : getTotalPlayAndWaitTimeMs() / foregroundPlaybackCount; 825 } 826 827 /** Returns the total time covered by any playback state, in milliseconds. */ getTotalElapsedTimeMs()828 public long getTotalElapsedTimeMs() { 829 long totalTimeMs = 0; 830 for (int i = 0; i < PLAYBACK_STATE_COUNT; i++) { 831 totalTimeMs += playbackStateDurationsMs[i]; 832 } 833 return totalTimeMs; 834 } 835 836 /** 837 * Returns the mean time covered by any playback state per playback, in milliseconds, or {@link 838 * C#TIME_UNSET} if no playback was recorded. 839 */ getMeanElapsedTimeMs()840 public long getMeanElapsedTimeMs() { 841 return playbackCount == 0 ? C.TIME_UNSET : getTotalElapsedTimeMs() / playbackCount; 842 } 843 844 /** 845 * Returns the ratio of foreground playbacks which were abandoned before they were ready to play, 846 * or {@code 0.0} if no playback has been in foreground. 847 */ getAbandonedBeforeReadyRatio()848 public float getAbandonedBeforeReadyRatio() { 849 int foregroundAbandonedBeforeReady = 850 abandonedBeforeReadyCount - (playbackCount - foregroundPlaybackCount); 851 return foregroundPlaybackCount == 0 852 ? 0f 853 : (float) foregroundAbandonedBeforeReady / foregroundPlaybackCount; 854 } 855 856 /** 857 * Returns the ratio of foreground playbacks which reached the ended state at least once, or 858 * {@code 0.0} if no playback has been in foreground. 859 */ getEndedRatio()860 public float getEndedRatio() { 861 return foregroundPlaybackCount == 0 ? 0f : (float) endedCount / foregroundPlaybackCount; 862 } 863 864 /** 865 * Returns the mean number of times a playback has been paused per foreground playback, or {@code 866 * 0.0} if no playback has been in foreground. 867 */ getMeanPauseCount()868 public float getMeanPauseCount() { 869 return foregroundPlaybackCount == 0 ? 0f : (float) totalPauseCount / foregroundPlaybackCount; 870 } 871 872 /** 873 * Returns the mean number of times a playback has been paused while rebuffering per foreground 874 * playback, or {@code 0.0} if no playback has been in foreground. 875 */ getMeanPauseBufferCount()876 public float getMeanPauseBufferCount() { 877 return foregroundPlaybackCount == 0 878 ? 0f 879 : (float) totalPauseBufferCount / foregroundPlaybackCount; 880 } 881 882 /** 883 * Returns the mean number of times a seek occurred per foreground playback, or {@code 0.0} if no 884 * playback has been in foreground. This includes seeks happening before playback resumed after 885 * another seek. 886 */ getMeanSeekCount()887 public float getMeanSeekCount() { 888 return foregroundPlaybackCount == 0 ? 0f : (float) totalSeekCount / foregroundPlaybackCount; 889 } 890 891 /** 892 * Returns the mean number of times a rebuffer occurred per foreground playback, or {@code 0.0} if 893 * no playback has been in foreground. This excludes initial joining and buffering after seek. 894 */ getMeanRebufferCount()895 public float getMeanRebufferCount() { 896 return foregroundPlaybackCount == 0 ? 0f : (float) totalRebufferCount / foregroundPlaybackCount; 897 } 898 899 /** 900 * Returns the ratio of wait times to the total time spent playing and waiting, or {@code 0.0} if 901 * no time was spend playing or waiting. This is equivalent to {@link #getTotalWaitTimeMs()} / 902 * {@link #getTotalPlayAndWaitTimeMs()} and also to {@link #getJoinTimeRatio()} + {@link 903 * #getRebufferTimeRatio()} + {@link #getSeekTimeRatio()}. 904 */ getWaitTimeRatio()905 public float getWaitTimeRatio() { 906 long playAndWaitTimeMs = getTotalPlayAndWaitTimeMs(); 907 return playAndWaitTimeMs == 0 ? 0f : (float) getTotalWaitTimeMs() / playAndWaitTimeMs; 908 } 909 910 /** 911 * Returns the ratio of foreground join time to the total time spent playing and waiting, or 912 * {@code 0.0} if no time was spend playing or waiting. This is equivalent to {@link 913 * #getTotalJoinTimeMs()} / {@link #getTotalPlayAndWaitTimeMs()}. 914 */ getJoinTimeRatio()915 public float getJoinTimeRatio() { 916 long playAndWaitTimeMs = getTotalPlayAndWaitTimeMs(); 917 return playAndWaitTimeMs == 0 ? 0f : (float) getTotalJoinTimeMs() / playAndWaitTimeMs; 918 } 919 920 /** 921 * Returns the ratio of rebuffer time to the total time spent playing and waiting, or {@code 0.0} 922 * if no time was spend playing or waiting. This is equivalent to {@link 923 * #getTotalRebufferTimeMs()} / {@link #getTotalPlayAndWaitTimeMs()}. 924 */ getRebufferTimeRatio()925 public float getRebufferTimeRatio() { 926 long playAndWaitTimeMs = getTotalPlayAndWaitTimeMs(); 927 return playAndWaitTimeMs == 0 ? 0f : (float) getTotalRebufferTimeMs() / playAndWaitTimeMs; 928 } 929 930 /** 931 * Returns the ratio of seek time to the total time spent playing and waiting, or {@code 0.0} if 932 * no time was spend playing or waiting. This is equivalent to {@link #getTotalSeekTimeMs()} / 933 * {@link #getTotalPlayAndWaitTimeMs()}. 934 */ getSeekTimeRatio()935 public float getSeekTimeRatio() { 936 long playAndWaitTimeMs = getTotalPlayAndWaitTimeMs(); 937 return playAndWaitTimeMs == 0 ? 0f : (float) getTotalSeekTimeMs() / playAndWaitTimeMs; 938 } 939 940 /** 941 * Returns the rate of rebuffer events, in rebuffers per play time second, or {@code 0.0} if no 942 * time was spend playing. This is equivalent to 1.0 / {@link #getMeanTimeBetweenRebuffers()}. 943 */ getRebufferRate()944 public float getRebufferRate() { 945 long playTimeMs = getTotalPlayTimeMs(); 946 return playTimeMs == 0 ? 0f : 1000f * totalRebufferCount / playTimeMs; 947 } 948 949 /** 950 * Returns the mean play time between rebuffer events, in seconds. This is equivalent to 1.0 / 951 * {@link #getRebufferRate()}. Note that this may return {@link Float#POSITIVE_INFINITY}. 952 */ getMeanTimeBetweenRebuffers()953 public float getMeanTimeBetweenRebuffers() { 954 return 1f / getRebufferRate(); 955 } 956 957 /** 958 * Returns the mean initial video format height, in pixels, or {@link C#LENGTH_UNSET} if no video 959 * format data is available. 960 */ getMeanInitialVideoFormatHeight()961 public int getMeanInitialVideoFormatHeight() { 962 return initialVideoFormatHeightCount == 0 963 ? C.LENGTH_UNSET 964 : totalInitialVideoFormatHeight / initialVideoFormatHeightCount; 965 } 966 967 /** 968 * Returns the mean initial video format bitrate, in bits per second, or {@link C#LENGTH_UNSET} if 969 * no video format data is available. 970 */ getMeanInitialVideoFormatBitrate()971 public int getMeanInitialVideoFormatBitrate() { 972 return initialVideoFormatBitrateCount == 0 973 ? C.LENGTH_UNSET 974 : (int) (totalInitialVideoFormatBitrate / initialVideoFormatBitrateCount); 975 } 976 977 /** 978 * Returns the mean initial audio format bitrate, in bits per second, or {@link C#LENGTH_UNSET} if 979 * no audio format data is available. 980 */ getMeanInitialAudioFormatBitrate()981 public int getMeanInitialAudioFormatBitrate() { 982 return initialAudioFormatBitrateCount == 0 983 ? C.LENGTH_UNSET 984 : (int) (totalInitialAudioFormatBitrate / initialAudioFormatBitrateCount); 985 } 986 987 /** 988 * Returns the mean video format height, in pixels, or {@link C#LENGTH_UNSET} if no video format 989 * data is available. This is a weighted average taking the time the format was used for playback 990 * into account. 991 */ getMeanVideoFormatHeight()992 public int getMeanVideoFormatHeight() { 993 return totalVideoFormatHeightTimeMs == 0 994 ? C.LENGTH_UNSET 995 : (int) (totalVideoFormatHeightTimeProduct / totalVideoFormatHeightTimeMs); 996 } 997 998 /** 999 * Returns the mean video format bitrate, in bits per second, or {@link C#LENGTH_UNSET} if no 1000 * video format data is available. This is a weighted average taking the time the format was used 1001 * for playback into account. 1002 */ getMeanVideoFormatBitrate()1003 public int getMeanVideoFormatBitrate() { 1004 return totalVideoFormatBitrateTimeMs == 0 1005 ? C.LENGTH_UNSET 1006 : (int) (totalVideoFormatBitrateTimeProduct / totalVideoFormatBitrateTimeMs); 1007 } 1008 1009 /** 1010 * Returns the mean audio format bitrate, in bits per second, or {@link C#LENGTH_UNSET} if no 1011 * audio format data is available. This is a weighted average taking the time the format was used 1012 * for playback into account. 1013 */ getMeanAudioFormatBitrate()1014 public int getMeanAudioFormatBitrate() { 1015 return totalAudioFormatTimeMs == 0 1016 ? C.LENGTH_UNSET 1017 : (int) (totalAudioFormatBitrateTimeProduct / totalAudioFormatTimeMs); 1018 } 1019 1020 /** 1021 * Returns the mean network bandwidth based on transfer measurements, in bits per second, or 1022 * {@link C#LENGTH_UNSET} if no transfer data is available. 1023 */ getMeanBandwidth()1024 public int getMeanBandwidth() { 1025 return totalBandwidthTimeMs == 0 1026 ? C.LENGTH_UNSET 1027 : (int) (totalBandwidthBytes * 8000 / totalBandwidthTimeMs); 1028 } 1029 1030 /** 1031 * Returns the mean rate at which video frames are dropped, in dropped frames per play time 1032 * second, or {@code 0.0} if no time was spent playing. 1033 */ getDroppedFramesRate()1034 public float getDroppedFramesRate() { 1035 long playTimeMs = getTotalPlayTimeMs(); 1036 return playTimeMs == 0 ? 0f : 1000f * totalDroppedFrames / playTimeMs; 1037 } 1038 1039 /** 1040 * Returns the mean rate at which audio underruns occurred, in underruns per play time second, or 1041 * {@code 0.0} if no time was spent playing. 1042 */ getAudioUnderrunRate()1043 public float getAudioUnderrunRate() { 1044 long playTimeMs = getTotalPlayTimeMs(); 1045 return playTimeMs == 0 ? 0f : 1000f * totalAudioUnderruns / playTimeMs; 1046 } 1047 1048 /** 1049 * Returns the ratio of foreground playbacks which experienced fatal errors, or {@code 0.0} if no 1050 * playback has been in foreground. 1051 */ getFatalErrorRatio()1052 public float getFatalErrorRatio() { 1053 return foregroundPlaybackCount == 0 1054 ? 0f 1055 : (float) fatalErrorPlaybackCount / foregroundPlaybackCount; 1056 } 1057 1058 /** 1059 * Returns the rate of fatal errors, in errors per play time second, or {@code 0.0} if no time was 1060 * spend playing. This is equivalent to 1.0 / {@link #getMeanTimeBetweenFatalErrors()}. 1061 */ getFatalErrorRate()1062 public float getFatalErrorRate() { 1063 long playTimeMs = getTotalPlayTimeMs(); 1064 return playTimeMs == 0 ? 0f : 1000f * fatalErrorCount / playTimeMs; 1065 } 1066 1067 /** 1068 * Returns the mean play time between fatal errors, in seconds. This is equivalent to 1.0 / {@link 1069 * #getFatalErrorRate()}. Note that this may return {@link Float#POSITIVE_INFINITY}. 1070 */ getMeanTimeBetweenFatalErrors()1071 public float getMeanTimeBetweenFatalErrors() { 1072 return 1f / getFatalErrorRate(); 1073 } 1074 1075 /** 1076 * Returns the mean number of non-fatal errors per foreground playback, or {@code 0.0} if no 1077 * playback has been in foreground. 1078 */ getMeanNonFatalErrorCount()1079 public float getMeanNonFatalErrorCount() { 1080 return foregroundPlaybackCount == 0 ? 0f : (float) nonFatalErrorCount / foregroundPlaybackCount; 1081 } 1082 1083 /** 1084 * Returns the rate of non-fatal errors, in errors per play time second, or {@code 0.0} if no time 1085 * was spend playing. This is equivalent to 1.0 / {@link #getMeanTimeBetweenNonFatalErrors()}. 1086 */ getNonFatalErrorRate()1087 public float getNonFatalErrorRate() { 1088 long playTimeMs = getTotalPlayTimeMs(); 1089 return playTimeMs == 0 ? 0f : 1000f * nonFatalErrorCount / playTimeMs; 1090 } 1091 1092 /** 1093 * Returns the mean play time between non-fatal errors, in seconds. This is equivalent to 1.0 / 1094 * {@link #getNonFatalErrorRate()}. Note that this may return {@link Float#POSITIVE_INFINITY}. 1095 */ getMeanTimeBetweenNonFatalErrors()1096 public float getMeanTimeBetweenNonFatalErrors() { 1097 return 1f / getNonFatalErrorRate(); 1098 } 1099 } 1100