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.annotation.SuppressLint; 24 import android.os.Bundle; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 28 import java.lang.annotation.Retention; 29 import java.util.Objects; 30 31 /** 32 * Playback error event. 33 */ 34 public final class PlaybackErrorEvent extends Event implements Parcelable { 35 /** Unknown error code. */ 36 public static final int ERROR_UNKNOWN = 0; 37 /** Error code for other errors */ 38 public static final int ERROR_OTHER = 1; 39 /** Error code for runtime errors */ 40 public static final int ERROR_RUNTIME = 2; 41 42 /** Error code for lack of network connectivity while trying to access a network resource */ 43 public static final int ERROR_IO_NETWORK_UNAVAILABLE = 3; 44 /** Error code for a failure while establishing a network connection */ 45 public static final int ERROR_IO_NETWORK_CONNECTION_FAILED = 4; 46 /** Error code for an HTTP server returning an unexpected HTTP response status code */ 47 public static final int ERROR_IO_BAD_HTTP_STATUS = 5; 48 /** Error code for failing to resolve a hostname */ 49 public static final int ERROR_IO_DNS_FAILED = 6; 50 /** 51 * Error code for a network timeout, meaning the server is taking too long to fulfill 52 * a request 53 */ 54 public static final int ERROR_IO_CONNECTION_TIMEOUT = 7; 55 /** Error code for an existing network connection being unexpectedly closed */ 56 public static final int ERROR_IO_CONNECTION_CLOSED = 8; 57 /** Error code for other Input/Output errors */ 58 public static final int ERROR_IO_OTHER = 9; 59 60 /** Error code for a parsing error associated to a media manifest */ 61 public static final int ERROR_PARSING_MANIFEST_MALFORMED = 10; 62 /** Error code for a parsing error associated to a media container format bitstream */ 63 public static final int ERROR_PARSING_CONTAINER_MALFORMED = 11; 64 /** Error code for other media parsing errors */ 65 public static final int ERROR_PARSING_OTHER = 12; 66 67 /** Error code for a decoder initialization failure */ 68 public static final int ERROR_DECODER_INIT_FAILED = 13; 69 /** Error code for a failure while trying to decode media samples */ 70 public static final int ERROR_DECODING_FAILED = 14; 71 /** 72 * Error code for trying to decode content whose format exceeds the capabilities of the device. 73 */ 74 public static final int ERROR_DECODING_FORMAT_EXCEEDS_CAPABILITIES = 15; 75 /** Error code for other decoding errors */ 76 public static final int ERROR_DECODING_OTHER = 16; 77 78 /** Error code for an AudioTrack initialization failure */ 79 public static final int ERROR_AUDIO_TRACK_INIT_FAILED = 17; 80 /** Error code for an AudioTrack write operation failure */ 81 public static final int ERROR_AUDIO_TRACK_WRITE_FAILED = 18; 82 /** Error code for other AudioTrack errors */ 83 public static final int ERROR_AUDIO_TRACK_OTHER = 19; 84 85 /** Error code for an unidentified error in a remote controller or player */ 86 public static final int ERROR_PLAYER_REMOTE = 20; 87 /** 88 * Error code for the loading position falling behind the sliding window of available live 89 * content. 90 */ 91 public static final int ERROR_PLAYER_BEHIND_LIVE_WINDOW = 21; 92 /** Error code for other player errors */ 93 public static final int ERROR_PLAYER_OTHER = 22; 94 95 /** Error code for a chosen DRM protection scheme not being supported by the device */ 96 public static final int ERROR_DRM_SCHEME_UNSUPPORTED = 23; 97 /** Error code for a failure while provisioning the device */ 98 public static final int ERROR_DRM_PROVISIONING_FAILED = 24; 99 /** Error code for a failure while trying to obtain a license */ 100 public static final int ERROR_DRM_LICENSE_ACQUISITION_FAILED = 25; 101 /** Error code an operation being disallowed by a license policy */ 102 public static final int ERROR_DRM_DISALLOWED_OPERATION = 26; 103 /** Error code for an error in the DRM system */ 104 public static final int ERROR_DRM_SYSTEM_ERROR = 27; 105 /** Error code for attempting to play incompatible DRM-protected content */ 106 public static final int ERROR_DRM_CONTENT_ERROR = 28; 107 /** Error code for the device having revoked DRM privileges */ 108 public static final int ERROR_DRM_DEVICE_REVOKED = 29; 109 /** Error code for other DRM errors */ 110 public static final int ERROR_DRM_OTHER = 30; 111 112 /** Error code for a non-existent file */ 113 public static final int ERROR_IO_FILE_NOT_FOUND = 31; 114 /** 115 * Error code for lack of permission to perform an IO operation, for example, lack of permission 116 * to access internet or external storage. 117 */ 118 public static final int ERROR_IO_NO_PERMISSION = 32; 119 120 /** Error code for an unsupported feature in a media manifest */ 121 public static final int ERROR_PARSING_MANIFEST_UNSUPPORTED = 33; 122 /** 123 * Error code for attempting to extract a file with an unsupported media container format, or an 124 * unsupported media container feature 125 */ 126 public static final int ERROR_PARSING_CONTAINER_UNSUPPORTED = 34; 127 128 /** Error code for trying to decode content whose format is not supported */ 129 public static final int ERROR_DECODING_FORMAT_UNSUPPORTED = 35; 130 131 132 private final @Nullable String mExceptionStack; 133 private final int mErrorCode; 134 private final int mSubErrorCode; 135 private final long mTimeSinceCreatedMillis; 136 137 138 /** @hide */ 139 @IntDef(prefix = "ERROR_", value = { 140 ERROR_UNKNOWN, 141 ERROR_OTHER, 142 ERROR_RUNTIME, 143 ERROR_IO_NETWORK_UNAVAILABLE, 144 ERROR_IO_NETWORK_CONNECTION_FAILED, 145 ERROR_IO_BAD_HTTP_STATUS, 146 ERROR_IO_DNS_FAILED, 147 ERROR_IO_CONNECTION_TIMEOUT, 148 ERROR_IO_CONNECTION_CLOSED, 149 ERROR_IO_OTHER, 150 ERROR_PARSING_MANIFEST_MALFORMED, 151 ERROR_PARSING_CONTAINER_MALFORMED, 152 ERROR_PARSING_OTHER, 153 ERROR_DECODER_INIT_FAILED, 154 ERROR_DECODING_FAILED, 155 ERROR_DECODING_FORMAT_EXCEEDS_CAPABILITIES, 156 ERROR_DECODING_OTHER, 157 ERROR_AUDIO_TRACK_INIT_FAILED, 158 ERROR_AUDIO_TRACK_WRITE_FAILED, 159 ERROR_AUDIO_TRACK_OTHER, 160 ERROR_PLAYER_REMOTE, 161 ERROR_PLAYER_BEHIND_LIVE_WINDOW, 162 ERROR_PLAYER_OTHER, 163 ERROR_DRM_SCHEME_UNSUPPORTED, 164 ERROR_DRM_PROVISIONING_FAILED, 165 ERROR_DRM_LICENSE_ACQUISITION_FAILED, 166 ERROR_DRM_DISALLOWED_OPERATION, 167 ERROR_DRM_SYSTEM_ERROR, 168 ERROR_DRM_CONTENT_ERROR, 169 ERROR_DRM_DEVICE_REVOKED, 170 ERROR_DRM_OTHER, 171 ERROR_IO_FILE_NOT_FOUND, 172 ERROR_IO_NO_PERMISSION, 173 ERROR_PARSING_MANIFEST_UNSUPPORTED, 174 ERROR_PARSING_CONTAINER_UNSUPPORTED, 175 ERROR_DECODING_FORMAT_UNSUPPORTED, 176 }) 177 @Retention(java.lang.annotation.RetentionPolicy.SOURCE) 178 public @interface ErrorCode {} 179 180 /** 181 * Creates a new PlaybackErrorEvent. 182 */ PlaybackErrorEvent( @ullable String exceptionStack, int errorCode, int subErrorCode, long timeSinceCreatedMillis, @NonNull Bundle extras)183 private PlaybackErrorEvent( 184 @Nullable String exceptionStack, 185 int errorCode, 186 int subErrorCode, 187 long timeSinceCreatedMillis, 188 @NonNull Bundle extras) { 189 this.mExceptionStack = exceptionStack; 190 this.mErrorCode = errorCode; 191 this.mSubErrorCode = subErrorCode; 192 this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; 193 this.mMetricsBundle = extras.deepCopy(); 194 } 195 196 /** @hide */ 197 @Nullable getExceptionStack()198 public String getExceptionStack() { 199 return mExceptionStack; 200 } 201 202 203 /** 204 * Gets error code. 205 */ 206 @ErrorCode getErrorCode()207 public int getErrorCode() { 208 return mErrorCode; 209 } 210 211 212 /** 213 * Gets sub error code. 214 */ 215 @IntRange(from = Integer.MIN_VALUE, to = Integer.MAX_VALUE) getSubErrorCode()216 public int getSubErrorCode() { 217 return mSubErrorCode; 218 } 219 220 /** 221 * Gets the timestamp since creation of the playback session in milliseconds. 222 * @return the timestamp since the playback is created, or -1 if unknown. 223 * @see LogSessionId 224 * @see PlaybackSession 225 */ 226 @Override 227 @IntRange(from = -1) getTimeSinceCreatedMillis()228 public long getTimeSinceCreatedMillis() { 229 return mTimeSinceCreatedMillis; 230 } 231 232 /** 233 * Gets metrics-related information that is not supported by dedicated methods. 234 * <p>It is intended to be used for backwards compatibility by the metrics infrastructure. 235 */ 236 @Override 237 @NonNull getMetricsBundle()238 public Bundle getMetricsBundle() { 239 return mMetricsBundle; 240 } 241 242 @Override toString()243 public String toString() { 244 return "PlaybackErrorEvent { " 245 + "exceptionStack = " + mExceptionStack + ", " 246 + "errorCode = " + mErrorCode + ", " 247 + "subErrorCode = " + mSubErrorCode + ", " 248 + "timeSinceCreatedMillis = " + mTimeSinceCreatedMillis 249 + " }"; 250 } 251 252 @Override equals(@ullable Object o)253 public boolean equals(@Nullable Object o) { 254 if (this == o) return true; 255 if (o == null || getClass() != o.getClass()) return false; 256 PlaybackErrorEvent that = (PlaybackErrorEvent) o; 257 return Objects.equals(mExceptionStack, that.mExceptionStack) 258 && mErrorCode == that.mErrorCode 259 && mSubErrorCode == that.mSubErrorCode 260 && mTimeSinceCreatedMillis == that.mTimeSinceCreatedMillis; 261 } 262 263 @Override hashCode()264 public int hashCode() { 265 return Objects.hash(mExceptionStack, mErrorCode, mSubErrorCode, 266 mTimeSinceCreatedMillis); 267 } 268 269 @Override writeToParcel(@onNull Parcel dest, int flags)270 public void writeToParcel(@NonNull Parcel dest, int flags) { 271 byte flg = 0; 272 if (mExceptionStack != null) flg |= 0x1; 273 dest.writeByte(flg); 274 if (mExceptionStack != null) dest.writeString(mExceptionStack); 275 dest.writeInt(mErrorCode); 276 dest.writeInt(mSubErrorCode); 277 dest.writeLong(mTimeSinceCreatedMillis); 278 dest.writeBundle(mMetricsBundle); 279 } 280 281 @Override describeContents()282 public int describeContents() { 283 return 0; 284 } 285 PlaybackErrorEvent(@onNull Parcel in)286 private PlaybackErrorEvent(@NonNull Parcel in) { 287 byte flg = in.readByte(); 288 String exceptionStack = (flg & 0x1) == 0 ? null : in.readString(); 289 int errorCode = in.readInt(); 290 int subErrorCode = in.readInt(); 291 long timeSinceCreatedMillis = in.readLong(); 292 Bundle extras = in.readBundle(); 293 294 this.mExceptionStack = exceptionStack; 295 this.mErrorCode = errorCode; 296 this.mSubErrorCode = subErrorCode; 297 this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; 298 this.mMetricsBundle = extras; 299 } 300 301 302 public static final @NonNull Parcelable.Creator<PlaybackErrorEvent> CREATOR = 303 new Parcelable.Creator<PlaybackErrorEvent>() { 304 @Override 305 public PlaybackErrorEvent[] newArray(int size) { 306 return new PlaybackErrorEvent[size]; 307 } 308 309 @Override 310 public PlaybackErrorEvent createFromParcel(@NonNull Parcel in) { 311 return new PlaybackErrorEvent(in); 312 } 313 }; 314 315 /** 316 * A builder for {@link PlaybackErrorEvent} 317 */ 318 public static final class Builder { 319 private @Nullable Exception mException; 320 private int mErrorCode = ERROR_UNKNOWN; 321 private int mSubErrorCode; 322 private long mTimeSinceCreatedMillis = -1; 323 private Bundle mMetricsBundle = new Bundle(); 324 325 /** 326 * Creates a new Builder. 327 */ Builder()328 public Builder() { 329 } 330 331 /** 332 * Sets the {@link Exception} object. 333 */ 334 @SuppressLint("MissingGetterMatchingBuilder") // Exception is not parcelable. setException(@onNull Exception value)335 public @NonNull Builder setException(@NonNull Exception value) { 336 mException = value; 337 return this; 338 } 339 340 /** 341 * Sets error code. 342 */ setErrorCode(@rrorCode int value)343 public @NonNull Builder setErrorCode(@ErrorCode int value) { 344 mErrorCode = value; 345 return this; 346 } 347 348 /** 349 * Sets sub error code. 350 */ setSubErrorCode( @ntRangefrom = Integer.MIN_VALUE, to = Integer.MAX_VALUE) int value)351 public @NonNull Builder setSubErrorCode( 352 @IntRange(from = Integer.MIN_VALUE, to = Integer.MAX_VALUE) int value) { 353 mSubErrorCode = value; 354 return this; 355 } 356 357 /** 358 * Set the timestamp since creation in milliseconds. 359 * @param value the timestamp since the creation in milliseconds. 360 * -1 indicates the value is unknown. 361 * @see #getTimeSinceCreatedMillis() 362 */ setTimeSinceCreatedMillis(@ntRangefrom = -1) long value)363 public @NonNull Builder setTimeSinceCreatedMillis(@IntRange(from = -1) long value) { 364 mTimeSinceCreatedMillis = value; 365 return this; 366 } 367 368 /** 369 * Sets metrics-related information that is not supported by dedicated 370 * methods. 371 * <p>It is intended to be used for backwards compatibility by the 372 * metrics infrastructure. 373 */ setMetricsBundle(@onNull Bundle metricsBundle)374 public @NonNull Builder setMetricsBundle(@NonNull Bundle metricsBundle) { 375 mMetricsBundle = metricsBundle; 376 return this; 377 } 378 379 /** Builds the instance. */ build()380 public @NonNull PlaybackErrorEvent build() { 381 382 String stack; 383 if (mException.getStackTrace() != null && mException.getStackTrace().length > 0) { 384 // TODO: a better definition of the stack trace 385 stack = mException.getStackTrace()[0].toString(); 386 } else { 387 stack = null; 388 } 389 390 PlaybackErrorEvent o = new PlaybackErrorEvent( 391 stack, 392 mErrorCode, 393 mSubErrorCode, 394 mTimeSinceCreatedMillis, 395 mMetricsBundle); 396 return o; 397 } 398 } 399 } 400