From 2175c432d79a3253f60d3cf3ac8edc4508d79f6e Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 14 May 2024 08:10:05 -0700 Subject: [PATCH] Add error code for codec reclaim This allows apps to better detect when the platform reclaims a codec. This requires adding the error code to MediaCodecDecoderException. PiperOrigin-RevId: 633588914 --- RELEASENOTES.md | 3 +++ .../androidx/media3/common/PlaybackException.java | 6 ++++++ .../exoplayer/analytics/MediaMetricsListener.java | 3 +-- .../mediacodec/MediaCodecDecoderException.java | 15 +++++++++++++++ .../exoplayer/mediacodec/MediaCodecRenderer.java | 12 +++++++----- 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index b71674728a..a738f70528 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -27,6 +27,9 @@ * Fix bug where silence skipping at the end of items can trigger a playback exception. * Add `clear` to `PreloadMediaSource` to discard the preloading period. + * Add new error code + `PlaybackException.ERROR_CODE_DECODING_RESOURCES_RECLAIMED` that is used + when codec resources are reclaimed for higher priority tasks. * Transformer: * Work around a decoder bug where the number of audio channels was capped at stereo when handling PCM input. diff --git a/libraries/common/src/main/java/androidx/media3/common/PlaybackException.java b/libraries/common/src/main/java/androidx/media3/common/PlaybackException.java index 5cdd8082f7..177f849eb9 100644 --- a/libraries/common/src/main/java/androidx/media3/common/PlaybackException.java +++ b/libraries/common/src/main/java/androidx/media3/common/PlaybackException.java @@ -212,6 +212,10 @@ public class PlaybackException extends Exception implements Bundleable { /** Caused by trying to decode content whose format is not supported. */ public static final int ERROR_CODE_DECODING_FORMAT_UNSUPPORTED = 4005; + // TODO: b/322943860 - Stabilize error code and add to IntDef + /** Caused by higher priority task reclaiming resources needed for decoding. */ + @UnstableApi public static final int ERROR_CODE_DECODING_RESOURCES_RECLAIMED = 4006; + // AudioTrack errors (5xxx). /** Caused by an AudioTrack initialization failure. */ @@ -327,6 +331,8 @@ public class PlaybackException extends Exception implements Bundleable { return "ERROR_CODE_DECODING_FORMAT_EXCEEDS_CAPABILITIES"; case ERROR_CODE_DECODING_FORMAT_UNSUPPORTED: return "ERROR_CODE_DECODING_FORMAT_UNSUPPORTED"; + case ERROR_CODE_DECODING_RESOURCES_RECLAIMED: + return "ERROR_CODE_DECODING_RESOURCES_RECLAIMED"; case ERROR_CODE_AUDIO_TRACK_INIT_FAILED: return "ERROR_CODE_AUDIO_TRACK_INIT_FAILED"; case ERROR_CODE_AUDIO_TRACK_WRITE_FAILED: diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/MediaMetricsListener.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/MediaMetricsListener.java index 38ce5e9437..8ec2802f56 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/MediaMetricsListener.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/MediaMetricsListener.java @@ -800,8 +800,7 @@ public final class MediaMetricsListener int subErrorCode = Util.getErrorCodeFromPlatformDiagnosticsInfo(diagnosticsInfo); return new ErrorInfo(PlaybackErrorEvent.ERROR_DECODER_INIT_FAILED, subErrorCode); } else if (cause instanceof MediaCodecDecoderException) { - @Nullable String diagnosticsInfo = ((MediaCodecDecoderException) cause).diagnosticInfo; - int subErrorCode = Util.getErrorCodeFromPlatformDiagnosticsInfo(diagnosticsInfo); + int subErrorCode = ((MediaCodecDecoderException) cause).errorCode; return new ErrorInfo(PlaybackErrorEvent.ERROR_DECODING_FAILED, subErrorCode); } else if (cause instanceof OutOfMemoryError) { return new ErrorInfo(PlaybackErrorEvent.ERROR_DECODING_FAILED, /* subErrorCode= */ 0); diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecDecoderException.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecDecoderException.java index 5255ca7288..1cc6217bd0 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecDecoderException.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecDecoderException.java @@ -32,10 +32,17 @@ public class MediaCodecDecoderException extends DecoderException { /** An optional developer-readable diagnostic information string. May be null. */ @Nullable public final String diagnosticInfo; + /** An optional error code reported by the codec. May be 0 if no error code could be obtained. */ + public final int errorCode; + public MediaCodecDecoderException(Throwable cause, @Nullable MediaCodecInfo codecInfo) { super("Decoder failed: " + (codecInfo == null ? null : codecInfo.name), cause); this.codecInfo = codecInfo; diagnosticInfo = Util.SDK_INT >= 21 ? getDiagnosticInfoV21(cause) : null; + errorCode = + Util.SDK_INT >= 23 + ? getErrorCodeV23(cause) + : Util.getErrorCodeFromPlatformDiagnosticsInfo(diagnosticInfo); } @RequiresApi(21) @@ -46,4 +53,12 @@ public class MediaCodecDecoderException extends DecoderException { } return null; } + + @RequiresApi(23) + private static int getErrorCodeV23(Throwable cause) { + if (cause instanceof MediaCodec.CodecException) { + return ((MediaCodec.CodecException) cause).getErrorCode(); + } + return 0; + } } diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java index debaa2b7cb..7f3c816255 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java @@ -847,11 +847,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer { if (isRecoverable) { releaseCodec(); } - throw createRendererException( - createDecoderException(e, getCodecInfo()), - inputFormat, - isRecoverable, - PlaybackException.ERROR_CODE_DECODING_FAILED); + MediaCodecDecoderException exception = createDecoderException(e, getCodecInfo()); + @PlaybackException.ErrorCode + int errorCode = + exception.errorCode == CodecException.ERROR_RECLAIMED + ? PlaybackException.ERROR_CODE_DECODING_RESOURCES_RECLAIMED + : PlaybackException.ERROR_CODE_DECODING_FAILED; + throw createRendererException(exception, inputFormat, isRecoverable, errorCode); } throw e; }