1 /* 2 * Copyright (C) 2024 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 android.media.metrics; 17 18 import static com.android.media.editing.flags.Flags.FLAG_ADD_MEDIA_METRICS_EDITING; 19 20 import android.annotation.FlaggedApi; 21 import android.annotation.FloatRange; 22 import android.annotation.IntDef; 23 import android.annotation.IntRange; 24 import android.annotation.LongDef; 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.os.Bundle; 28 import android.os.Parcel; 29 import android.os.Parcelable; 30 31 import java.lang.annotation.Retention; 32 import java.util.ArrayList; 33 import java.util.List; 34 import java.util.Objects; 35 36 /** Event for an editing operation having ended. */ 37 @FlaggedApi(FLAG_ADD_MEDIA_METRICS_EDITING) 38 public final class EditingEndedEvent extends Event implements Parcelable { 39 40 // The special value 0 is reserved for the field being unspecified in the proto. 41 42 /** The editing operation was successful. */ 43 public static final int FINAL_STATE_SUCCEEDED = 1; 44 45 /** The editing operation was canceled. */ 46 public static final int FINAL_STATE_CANCELED = 2; 47 48 /** The editing operation failed due to an error. */ 49 public static final int FINAL_STATE_ERROR = 3; 50 51 /** @hide */ 52 @IntDef( 53 prefix = {"FINAL_STATE_"}, 54 value = { 55 FINAL_STATE_SUCCEEDED, 56 FINAL_STATE_CANCELED, 57 FINAL_STATE_ERROR, 58 }) 59 @Retention(java.lang.annotation.RetentionPolicy.SOURCE) 60 public @interface FinalState {} 61 62 private final @FinalState int mFinalState; 63 64 private final float mFinalProgressPercent; 65 66 // The special value 0 is reserved for the field being unspecified in the proto. 67 68 /** Special value representing that no error occurred. */ 69 public static final int ERROR_CODE_NONE = 1; 70 71 /** Error code for unexpected runtime errors. */ 72 public static final int ERROR_CODE_FAILED_RUNTIME_CHECK = 2; 73 74 /** Error code for non-specific errors during input/output. */ 75 public static final int ERROR_CODE_IO_UNSPECIFIED = 3; 76 77 /** Error code for network connection failures. */ 78 public static final int ERROR_CODE_IO_NETWORK_CONNECTION_FAILED = 4; 79 80 /** Error code for network timeouts. */ 81 public static final int ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT = 5; 82 83 /** Caused by an HTTP server returning an unexpected HTTP response status code. */ 84 public static final int ERROR_CODE_IO_BAD_HTTP_STATUS = 6; 85 86 /** Caused by a non-existent file. */ 87 public static final int ERROR_CODE_IO_FILE_NOT_FOUND = 7; 88 89 /** 90 * Caused by lack of permission to perform an IO operation. For example, lack of permission to 91 * access internet or external storage. 92 */ 93 public static final int ERROR_CODE_IO_NO_PERMISSION = 8; 94 95 /** 96 * Caused by failing to load data via cleartext HTTP, when the app's network security 97 * configuration does not permit it. 98 */ 99 public static final int ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED = 9; 100 101 /** Caused by reading data out of the data bounds. */ 102 public static final int ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE = 10; 103 104 /** Caused by a decoder initialization failure. */ 105 public static final int ERROR_CODE_DECODER_INIT_FAILED = 11; 106 107 /** Caused by a failure while trying to decode media samples. */ 108 public static final int ERROR_CODE_DECODING_FAILED = 12; 109 110 /** Caused by trying to decode content whose format is not supported. */ 111 public static final int ERROR_CODE_DECODING_FORMAT_UNSUPPORTED = 13; 112 113 /** Caused by an encoder initialization failure. */ 114 public static final int ERROR_CODE_ENCODER_INIT_FAILED = 14; 115 116 /** Caused by a failure while trying to encode media samples. */ 117 public static final int ERROR_CODE_ENCODING_FAILED = 15; 118 119 /** Caused by trying to encode content whose format is not supported. */ 120 public static final int ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED = 16; 121 122 /** Caused by a video frame processing failure. */ 123 public static final int ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED = 17; 124 125 /** Caused by an audio processing failure. */ 126 public static final int ERROR_CODE_AUDIO_PROCESSING_FAILED = 18; 127 128 /** Caused by a failure while muxing media samples. */ 129 public static final int ERROR_CODE_MUXING_FAILED = 19; 130 131 /** @hide */ 132 @IntDef( 133 prefix = {"ERROR_CODE_"}, 134 value = { 135 ERROR_CODE_NONE, 136 ERROR_CODE_FAILED_RUNTIME_CHECK, 137 ERROR_CODE_IO_UNSPECIFIED, 138 ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, 139 ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT, 140 ERROR_CODE_IO_BAD_HTTP_STATUS, 141 ERROR_CODE_IO_FILE_NOT_FOUND, 142 ERROR_CODE_IO_NO_PERMISSION, 143 ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED, 144 ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE, 145 ERROR_CODE_DECODER_INIT_FAILED, 146 ERROR_CODE_DECODING_FAILED, 147 ERROR_CODE_DECODING_FORMAT_UNSUPPORTED, 148 ERROR_CODE_ENCODER_INIT_FAILED, 149 ERROR_CODE_ENCODING_FAILED, 150 ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED, 151 ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED, 152 ERROR_CODE_AUDIO_PROCESSING_FAILED, 153 ERROR_CODE_MUXING_FAILED, 154 }) 155 @Retention(java.lang.annotation.RetentionPolicy.SOURCE) 156 public @interface ErrorCode {} 157 158 /** Special value for unknown {@linkplain #getTimeSinceCreatedMillis() time since creation}. */ 159 public static final int TIME_SINCE_CREATED_UNKNOWN = -1; 160 161 /** Special value for unknown {@linkplain #getFinalProgressPercent() final progress}. */ 162 public static final int PROGRESS_PERCENT_UNKNOWN = -1; 163 164 private final @ErrorCode int mErrorCode; 165 @SuppressWarnings("HidingField") // Hiding field from superclass as for playback events. 166 private final long mTimeSinceCreatedMillis; 167 168 @Nullable private final String mExporterName; 169 @Nullable private final String mMuxerName; 170 private final ArrayList<MediaItemInfo> mInputMediaItemInfos; 171 @Nullable private final MediaItemInfo mOutputMediaItemInfo; 172 173 /** @hide */ 174 @LongDef( 175 prefix = {"OPERATION_TYPE_"}, 176 flag = true, 177 value = { 178 OPERATION_TYPE_VIDEO_TRANSCODE, 179 OPERATION_TYPE_AUDIO_TRANSCODE, 180 OPERATION_TYPE_VIDEO_EDIT, 181 OPERATION_TYPE_AUDIO_EDIT, 182 OPERATION_TYPE_VIDEO_TRANSMUX, 183 OPERATION_TYPE_AUDIO_TRANSMUX, 184 OPERATION_TYPE_PAUSED, 185 OPERATION_TYPE_RESUMED, 186 }) 187 @Retention(java.lang.annotation.RetentionPolicy.SOURCE) 188 public @interface OperationType {} 189 190 /** Input video was decoded and re-encoded. */ 191 public static final long OPERATION_TYPE_VIDEO_TRANSCODE = 1; 192 193 /** Input audio was decoded and re-encoded. */ 194 public static final long OPERATION_TYPE_AUDIO_TRANSCODE = 1L << 1; 195 196 /** Input video was edited. */ 197 public static final long OPERATION_TYPE_VIDEO_EDIT = 1L << 2; 198 199 /** Input audio was edited. */ 200 public static final long OPERATION_TYPE_AUDIO_EDIT = 1L << 3; 201 202 /** Input video samples were written (muxed) directly to the output file without transcoding. */ 203 public static final long OPERATION_TYPE_VIDEO_TRANSMUX = 1L << 4; 204 205 /** Input audio samples were written (muxed) directly to the output file without transcoding. */ 206 public static final long OPERATION_TYPE_AUDIO_TRANSMUX = 1L << 5; 207 208 /** The editing operation was paused before it completed. */ 209 public static final long OPERATION_TYPE_PAUSED = 1L << 6; 210 211 /** The editing operation resumed a previous (paused) operation. */ 212 public static final long OPERATION_TYPE_RESUMED = 1L << 7; 213 214 private final @OperationType long mOperationTypes; 215 EditingEndedEvent( @inalState int finalState, float finalProgressPercent, @ErrorCode int errorCode, long timeSinceCreatedMillis, @Nullable String exporterName, @Nullable String muxerName, ArrayList<MediaItemInfo> inputMediaItemInfos, @Nullable MediaItemInfo outputMediaItemInfo, @OperationType long operationTypes, @NonNull Bundle extras)216 private EditingEndedEvent( 217 @FinalState int finalState, 218 float finalProgressPercent, 219 @ErrorCode int errorCode, 220 long timeSinceCreatedMillis, 221 @Nullable String exporterName, 222 @Nullable String muxerName, 223 ArrayList<MediaItemInfo> inputMediaItemInfos, 224 @Nullable MediaItemInfo outputMediaItemInfo, 225 @OperationType long operationTypes, 226 @NonNull Bundle extras) { 227 mFinalState = finalState; 228 mFinalProgressPercent = finalProgressPercent; 229 mErrorCode = errorCode; 230 mTimeSinceCreatedMillis = timeSinceCreatedMillis; 231 mExporterName = exporterName; 232 mMuxerName = muxerName; 233 mInputMediaItemInfos = inputMediaItemInfos; 234 mOutputMediaItemInfo = outputMediaItemInfo; 235 mOperationTypes = operationTypes; 236 mMetricsBundle = extras.deepCopy(); 237 } 238 239 /** Returns the state of the editing session when it ended. */ 240 @FinalState getFinalState()241 public int getFinalState() { 242 return mFinalState; 243 } 244 245 /** 246 * Returns the progress of the editing operation in percent at the moment that it ended, or 247 * {@link #PROGRESS_PERCENT_UNKNOWN} if unknown. 248 */ getFinalProgressPercent()249 public float getFinalProgressPercent() { 250 return mFinalProgressPercent; 251 } 252 253 /** Returns the error code for a {@linkplain #FINAL_STATE_ERROR failed} editing session. */ 254 @ErrorCode getErrorCode()255 public int getErrorCode() { 256 return mErrorCode; 257 } 258 259 /** 260 * Gets the elapsed time since creating of the editing session, in milliseconds, or {@link 261 * #TIME_SINCE_CREATED_UNKNOWN} if unknown. 262 * 263 * @return The elapsed time since creating the editing session, in milliseconds, or {@link 264 * #TIME_SINCE_CREATED_UNKNOWN} if unknown. 265 * @see LogSessionId 266 * @see EditingSession 267 */ 268 @Override 269 @IntRange(from = TIME_SINCE_CREATED_UNKNOWN) getTimeSinceCreatedMillis()270 public long getTimeSinceCreatedMillis() { 271 return mTimeSinceCreatedMillis; 272 } 273 274 /** 275 * Returns the name of the library implementing the exporting operation, for example, a Maven 276 * artifact ID like "androidx.media3.media3-transformer:1.3.0-beta01", or {@code null} if 277 * unknown. 278 */ 279 @Nullable getExporterName()280 public String getExporterName() { 281 return mExporterName; 282 } 283 284 /** 285 * Returns the name of the library implementing the media muxing operation, for example, a Maven 286 * artifact ID like "androidx.media3.media3-muxer:1.3.0-beta01", or {@code null} if unknown. 287 */ 288 @Nullable getMuxerName()289 public String getMuxerName() { 290 return mMuxerName; 291 } 292 293 /** Gets information about the input media items, or an empty list if unspecified. */ 294 @NonNull getInputMediaItemInfos()295 public List<MediaItemInfo> getInputMediaItemInfos() { 296 return new ArrayList<>(mInputMediaItemInfos); 297 } 298 299 /** Gets information about the output media item, or {@code null} if unspecified. */ 300 @Nullable getOutputMediaItemInfo()301 public MediaItemInfo getOutputMediaItemInfo() { 302 return mOutputMediaItemInfo; 303 } 304 305 /** Gets a set of flags describing the types of operations performed. */ getOperationTypes()306 public @OperationType long getOperationTypes() { 307 return mOperationTypes; 308 } 309 310 /** 311 * Gets metrics-related information that is not supported by dedicated methods. 312 * 313 * <p>It is intended to be used for backwards compatibility by the metrics infrastructure. 314 */ 315 @Override 316 @NonNull getMetricsBundle()317 public Bundle getMetricsBundle() { 318 return mMetricsBundle; 319 } 320 321 @Override 322 @NonNull toString()323 public String toString() { 324 return "EditingEndedEvent { " 325 + "finalState = " 326 + mFinalState 327 + ", " 328 + "finalProgressPercent = " 329 + mFinalProgressPercent 330 + ", " 331 + "errorCode = " 332 + mErrorCode 333 + ", " 334 + "timeSinceCreatedMillis = " 335 + mTimeSinceCreatedMillis 336 + ", " 337 + "exporterName = " 338 + mExporterName 339 + ", " 340 + "muxerName = " 341 + mMuxerName 342 + ", " 343 + "inputMediaItemInfos = " 344 + mInputMediaItemInfos 345 + ", " 346 + "outputMediaItemInfo = " 347 + mOutputMediaItemInfo 348 + ", " 349 + "operationTypes = " 350 + mOperationTypes 351 + " }"; 352 } 353 354 @Override equals(@ullable Object o)355 public boolean equals(@Nullable Object o) { 356 if (this == o) return true; 357 if (o == null || getClass() != o.getClass()) return false; 358 EditingEndedEvent that = (EditingEndedEvent) o; 359 return mFinalState == that.mFinalState 360 && mFinalProgressPercent == that.mFinalProgressPercent 361 && mErrorCode == that.mErrorCode 362 && Objects.equals(mInputMediaItemInfos, that.mInputMediaItemInfos) 363 && Objects.equals(mOutputMediaItemInfo, that.mOutputMediaItemInfo) 364 && mOperationTypes == that.mOperationTypes 365 && mTimeSinceCreatedMillis == that.mTimeSinceCreatedMillis 366 && Objects.equals(mExporterName, that.mExporterName) 367 && Objects.equals(mMuxerName, that.mMuxerName); 368 } 369 370 @Override hashCode()371 public int hashCode() { 372 return Objects.hash( 373 mFinalState, 374 mFinalProgressPercent, 375 mErrorCode, 376 mInputMediaItemInfos, 377 mOutputMediaItemInfo, 378 mOperationTypes, 379 mTimeSinceCreatedMillis, 380 mExporterName, 381 mMuxerName); 382 } 383 384 @Override writeToParcel(@onNull Parcel dest, int flags)385 public void writeToParcel(@NonNull Parcel dest, int flags) { 386 dest.writeInt(mFinalState); 387 dest.writeFloat(mFinalProgressPercent); 388 dest.writeInt(mErrorCode); 389 dest.writeLong(mTimeSinceCreatedMillis); 390 dest.writeString(mExporterName); 391 dest.writeString(mMuxerName); 392 dest.writeTypedList(mInputMediaItemInfos); 393 dest.writeTypedObject(mOutputMediaItemInfo, /* parcelableFlags= */ 0); 394 dest.writeLong(mOperationTypes); 395 dest.writeBundle(mMetricsBundle); 396 } 397 398 @Override describeContents()399 public int describeContents() { 400 return 0; 401 } 402 EditingEndedEvent(@onNull Parcel in)403 private EditingEndedEvent(@NonNull Parcel in) { 404 mFinalState = in.readInt(); 405 mFinalProgressPercent = in.readFloat(); 406 mErrorCode = in.readInt(); 407 mTimeSinceCreatedMillis = in.readLong(); 408 mExporterName = in.readString(); 409 mMuxerName = in.readString(); 410 mInputMediaItemInfos = new ArrayList<>(); 411 in.readTypedList(mInputMediaItemInfos, MediaItemInfo.CREATOR); 412 mOutputMediaItemInfo = in.readTypedObject(MediaItemInfo.CREATOR); 413 mOperationTypes = in.readLong(); 414 mMetricsBundle = in.readBundle(); 415 } 416 417 public static final @NonNull Creator<EditingEndedEvent> CREATOR = 418 new Creator<>() { 419 @Override 420 public EditingEndedEvent[] newArray(int size) { 421 return new EditingEndedEvent[size]; 422 } 423 424 @Override 425 public EditingEndedEvent createFromParcel(@NonNull Parcel in) { 426 return new EditingEndedEvent(in); 427 } 428 }; 429 430 /** Builder for {@link EditingEndedEvent} */ 431 @FlaggedApi(FLAG_ADD_MEDIA_METRICS_EDITING) 432 public static final class Builder { 433 private final @FinalState int mFinalState; 434 private final ArrayList<MediaItemInfo> mInputMediaItemInfos; 435 private float mFinalProgressPercent; 436 private @ErrorCode int mErrorCode; 437 private long mTimeSinceCreatedMillis; 438 @Nullable private String mExporterName; 439 @Nullable private String mMuxerName; 440 @Nullable private MediaItemInfo mOutputMediaItemInfo; 441 private @OperationType long mOperationTypes; 442 private Bundle mMetricsBundle; 443 444 /** 445 * Creates a new Builder. 446 * 447 * @param finalState The state of the editing session when it ended. 448 */ Builder(@inalState int finalState)449 public Builder(@FinalState int finalState) { 450 mFinalState = finalState; 451 mFinalProgressPercent = PROGRESS_PERCENT_UNKNOWN; 452 mErrorCode = ERROR_CODE_NONE; 453 mTimeSinceCreatedMillis = TIME_SINCE_CREATED_UNKNOWN; 454 mInputMediaItemInfos = new ArrayList<>(); 455 mMetricsBundle = new Bundle(); 456 } 457 458 /** 459 * Sets the progress of the editing operation in percent at the moment that it ended. 460 * 461 * @param finalProgressPercent The progress of the editing operation in percent at the 462 * moment that it ended. 463 * @see #getFinalProgressPercent() 464 */ setFinalProgressPercent( @loatRangefrom = 0, to = 100) float finalProgressPercent)465 public @NonNull Builder setFinalProgressPercent( 466 @FloatRange(from = 0, to = 100) float finalProgressPercent) { 467 mFinalProgressPercent = finalProgressPercent; 468 return this; 469 } 470 471 /** 472 * Sets the elapsed time since creating the editing session, in milliseconds. 473 * 474 * @param timeSinceCreatedMillis The elapsed time since creating the editing session, in 475 * milliseconds, or {@link #TIME_SINCE_CREATED_UNKNOWN} if unknown. 476 * @see #getTimeSinceCreatedMillis() 477 */ setTimeSinceCreatedMillis( @ntRangefrom = TIME_SINCE_CREATED_UNKNOWN) long timeSinceCreatedMillis)478 public @NonNull Builder setTimeSinceCreatedMillis( 479 @IntRange(from = TIME_SINCE_CREATED_UNKNOWN) long timeSinceCreatedMillis) { 480 mTimeSinceCreatedMillis = timeSinceCreatedMillis; 481 return this; 482 } 483 484 /** 485 * The name of the library implementing the exporting operation. For example, a Maven 486 * artifact ID like "androidx.media3.media3-transformer:1.3.0-beta01". 487 * 488 * @param exporterName The name of the library implementing the export operation. 489 * @see #getExporterName() 490 */ setExporterName(@onNull String exporterName)491 public @NonNull Builder setExporterName(@NonNull String exporterName) { 492 mExporterName = Objects.requireNonNull(exporterName); 493 return this; 494 } 495 496 /** 497 * The name of the library implementing the media muxing operation. For example, a Maven 498 * artifact ID like "androidx.media3.media3-muxer:1.3.0-beta01". 499 * 500 * @param muxerName The name of the library implementing the media muxing operation. 501 * @see #getMuxerName() 502 */ setMuxerName(@onNull String muxerName)503 public @NonNull Builder setMuxerName(@NonNull String muxerName) { 504 mMuxerName = Objects.requireNonNull(muxerName); 505 return this; 506 } 507 508 /** Sets the error code for a {@linkplain #FINAL_STATE_ERROR failed} editing session. */ setErrorCode(@rrorCode int value)509 public @NonNull Builder setErrorCode(@ErrorCode int value) { 510 mErrorCode = value; 511 return this; 512 } 513 514 /** Adds information about a media item that was input to the editing operation. */ addInputMediaItemInfo(@onNull MediaItemInfo mediaItemInfo)515 public @NonNull Builder addInputMediaItemInfo(@NonNull MediaItemInfo mediaItemInfo) { 516 mInputMediaItemInfos.add(Objects.requireNonNull(mediaItemInfo)); 517 return this; 518 } 519 520 /** Sets information about the output media item. */ setOutputMediaItemInfo(@onNull MediaItemInfo mediaItemInfo)521 public @NonNull Builder setOutputMediaItemInfo(@NonNull MediaItemInfo mediaItemInfo) { 522 mOutputMediaItemInfo = Objects.requireNonNull(mediaItemInfo); 523 return this; 524 } 525 526 /** 527 * Adds an operation type to the set of operations performed. 528 * 529 * @param operationType A type of operation performed as part of this editing operation. 530 */ addOperationType(@perationType long operationType)531 public @NonNull Builder addOperationType(@OperationType long operationType) { 532 mOperationTypes |= operationType; 533 return this; 534 } 535 536 /** 537 * Sets metrics-related information that is not supported by dedicated methods. 538 * 539 * <p>Used for backwards compatibility by the metrics infrastructure. 540 */ setMetricsBundle(@onNull Bundle metricsBundle)541 public @NonNull Builder setMetricsBundle(@NonNull Bundle metricsBundle) { 542 mMetricsBundle = Objects.requireNonNull(metricsBundle); 543 return this; 544 } 545 546 /** Builds an instance. */ build()547 public @NonNull EditingEndedEvent build() { 548 return new EditingEndedEvent( 549 mFinalState, 550 mFinalProgressPercent, 551 mErrorCode, 552 mTimeSinceCreatedMillis, 553 mExporterName, 554 mMuxerName, 555 mInputMediaItemInfos, 556 mOutputMediaItemInfo, 557 mOperationTypes, 558 mMetricsBundle); 559 } 560 } 561 562 } 563