From ffbec2234df4b741e80f7ce86480099c730d8529 Mon Sep 17 00:00:00 2001 From: claincly Date: Mon, 28 Jun 2021 14:39:33 +0100 Subject: [PATCH] Assign PlaybackException.ErrorCode to renderer failures. PiperOrigin-RevId: 381852092 --- .../exoplayer2/ExoPlaybackException.java | 10 ++++-- .../android/exoplayer2/PlaybackException.java | 11 +++++-- .../exoplayer2/ExoPlaybackExceptionTest.java | 3 +- .../exoplayer2/PlaybackExceptionTest.java | 2 +- .../android/exoplayer2/BaseRenderer.java | 32 ++++++++++++++++--- .../audio/DecoderAudioRenderer.java | 28 ++++++++++------ .../audio/MediaCodecAudioRenderer.java | 13 +++++--- .../mediacodec/MediaCodecRenderer.java | 22 ++++++++++--- .../video/DecoderVideoRenderer.java | 9 ++++-- 9 files changed, 96 insertions(+), 34 deletions(-) diff --git a/library/common/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java b/library/common/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java index 8a1bdcff70..1be297a2f1 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java @@ -170,7 +170,8 @@ public final class ExoPlaybackException extends PlaybackException { rendererIndex, rendererFormat, rendererFormatSupport, - /* isRecoverable= */ false); + /* isRecoverable= */ false, + ERROR_CODE_UNSPECIFIED); } /** @@ -183,6 +184,7 @@ public final class ExoPlaybackException extends PlaybackException { * @param rendererFormatSupport The {@link FormatSupport} of the renderer for {@code * rendererFormat}. Ignored if {@code rendererFormat} is null. * @param isRecoverable If the failure can be recovered by disabling and re-enabling the renderer. + * @param errorCode See {@link #errorCode}. * @return The created instance. */ public static ExoPlaybackException createForRenderer( @@ -191,12 +193,14 @@ public final class ExoPlaybackException extends PlaybackException { int rendererIndex, @Nullable Format rendererFormat, @FormatSupport int rendererFormatSupport, - boolean isRecoverable) { + boolean isRecoverable, + @ErrorCode int errorCode) { + return new ExoPlaybackException( TYPE_RENDERER, cause, /* customMessage= */ null, - ERROR_CODE_UNSPECIFIED, + errorCode, rendererName, rendererIndex, rendererFormat, diff --git a/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java b/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java index 419acf566f..29ee975ccc 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java @@ -61,6 +61,7 @@ public class PlaybackException extends Exception implements Bundleable { ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED, ERROR_CODE_PARSING_MANIFEST_UNSUPPORTED, ERROR_CODE_DECODER_INIT_FAILED, + ERROR_CODE_DECODER_QUERY_FAILED, ERROR_CODE_DECODING_FAILED, ERROR_CODE_DECODING_FORMAT_EXCEEDS_CAPABILITIES, ERROR_CODE_DECODING_FORMAT_UNSUPPORTED, @@ -144,12 +145,14 @@ public class PlaybackException extends Exception implements Bundleable { /** Caused by a decoder initialization failure. */ public static final int ERROR_CODE_DECODER_INIT_FAILED = 4001; + /** Caused by a decoder query failure. */ + public static final int ERROR_CODE_DECODER_QUERY_FAILED = 4002; /** Caused by a failure while trying to decode media samples. */ - public static final int ERROR_CODE_DECODING_FAILED = 4002; + public static final int ERROR_CODE_DECODING_FAILED = 4003; /** Caused by trying to decode content whose format exceeds the capabilities of the device. */ - public static final int ERROR_CODE_DECODING_FORMAT_EXCEEDS_CAPABILITIES = 4003; + public static final int ERROR_CODE_DECODING_FORMAT_EXCEEDS_CAPABILITIES = 4004; /** Caused by trying to decode content whose format is not supported. */ - public static final int ERROR_CODE_DECODING_FORMAT_UNSUPPORTED = 4004; + public static final int ERROR_CODE_DECODING_FORMAT_UNSUPPORTED = 4005; // AudioTrack errors (5xxx). @@ -223,6 +226,8 @@ public class PlaybackException extends Exception implements Bundleable { return "ERROR_CODE_PARSING_MANIFEST_UNSUPPORTED"; case ERROR_CODE_DECODER_INIT_FAILED: return "ERROR_CODE_DECODER_INIT_FAILED"; + case ERROR_CODE_DECODER_QUERY_FAILED: + return "ERROR_CODE_DECODER_QUERY_FAILED"; case ERROR_CODE_DECODING_FAILED: return "ERROR_CODE_DECODING_FAILED"; case ERROR_CODE_DECODING_FORMAT_EXCEEDS_CAPABILITIES: diff --git a/library/common/src/test/java/com/google/android/exoplayer2/ExoPlaybackExceptionTest.java b/library/common/src/test/java/com/google/android/exoplayer2/ExoPlaybackExceptionTest.java index 5c8372b466..b5b8e2a7b9 100644 --- a/library/common/src/test/java/com/google/android/exoplayer2/ExoPlaybackExceptionTest.java +++ b/library/common/src/test/java/com/google/android/exoplayer2/ExoPlaybackExceptionTest.java @@ -51,7 +51,8 @@ public class ExoPlaybackExceptionTest { /* rendererIndex= */ 123, /* rendererFormat= */ new Format.Builder().setCodecs("anyCodec").build(), /* rendererFormatSupport= */ C.FORMAT_UNSUPPORTED_SUBTYPE, - /* isRecoverable= */ true); + /* isRecoverable= */ true, + /* errorCode= */ PlaybackException.ERROR_CODE_DECODER_INIT_FAILED); ExoPlaybackException after = ExoPlaybackException.CREATOR.fromBundle(before.toBundle()); assertThat(areExoPlaybackExceptionsEqual(before, after)).isTrue(); diff --git a/library/common/src/test/java/com/google/android/exoplayer2/PlaybackExceptionTest.java b/library/common/src/test/java/com/google/android/exoplayer2/PlaybackExceptionTest.java index 527b5ecc2b..e5e94c911d 100644 --- a/library/common/src/test/java/com/google/android/exoplayer2/PlaybackExceptionTest.java +++ b/library/common/src/test/java/com/google/android/exoplayer2/PlaybackExceptionTest.java @@ -78,7 +78,7 @@ public class PlaybackExceptionTest { Bundle bundle = exception.toBundle(); assertThat(bundle.getString("0")).isEqualTo(PlaybackException.class.getName()); - assertThat(bundle.getInt("1")).isEqualTo(4002); // Error code. + assertThat(bundle.getInt("1")).isEqualTo(4003); // Error code. assertThat(bundle.getLong("2")).isEqualTo(2000); // Timestamp. assertThat(bundle.getString("3")).isEqualTo("message"); assertThat(bundle.getString("4")).isEqualTo(cause.getClass().getName()); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java index d8ca903433..8de7c4cf3f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java @@ -336,12 +336,28 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { * Creates an {@link ExoPlaybackException} of type {@link ExoPlaybackException#TYPE_RENDERER} for * this renderer. * - * @param cause The cause of the exception. - * @param format The current format used by the renderer. May be null. + *

Equivalent to {@link #createRendererException(Throwable, Format, int) + * createRendererException(cause, format, PlaybackException.ERROR_CODE_UNSPECIFIED)}. */ protected final ExoPlaybackException createRendererException( Throwable cause, @Nullable Format format) { - return createRendererException(cause, format, /* isRecoverable= */ false); + return createRendererException(cause, format, PlaybackException.ERROR_CODE_UNSPECIFIED); + } + + /** + * Creates an {@link ExoPlaybackException} of type {@link ExoPlaybackException#TYPE_RENDERER} for + * this renderer. + * + * @param cause The cause of the exception. + * @param format The current format used by the renderer. May be null. + * @param errorCode A {@link PlaybackException.ErrorCode} to identify the cause of the playback + * failure. + * @return The created instance, in which {@link ExoPlaybackException#isRecoverable} is {@code + * false}. + */ + protected final ExoPlaybackException createRendererException( + Throwable cause, @Nullable Format format, @PlaybackException.ErrorCode int errorCode) { + return createRendererException(cause, format, /* isRecoverable= */ false, errorCode); } /** @@ -351,9 +367,15 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { * @param cause The cause of the exception. * @param format The current format used by the renderer. May be null. * @param isRecoverable If the error is recoverable by disabling and re-enabling the renderer. + * @param errorCode A {@link PlaybackException.ErrorCode} to identify the cause of the playback + * failure. + * @return The created instance. */ protected final ExoPlaybackException createRendererException( - Throwable cause, @Nullable Format format, boolean isRecoverable) { + Throwable cause, + @Nullable Format format, + boolean isRecoverable, + @PlaybackException.ErrorCode int errorCode) { @C.FormatSupport int formatSupport = C.FORMAT_HANDLED; if (format != null && !throwRendererExceptionIsExecuting) { // Prevent recursive re-entry from subclass supportsFormat implementations. @@ -367,7 +389,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { } } return ExoPlaybackException.createForRenderer( - cause, getName(), getIndex(), format, formatSupport, isRecoverable); + cause, getName(), getIndex(), format, formatSupport, isRecoverable, errorCode); } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java index fb078c0054..286efe08e1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java @@ -32,6 +32,7 @@ import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlayerMessage.Target; import com.google.android.exoplayer2.RendererCapabilities; @@ -258,7 +259,8 @@ public abstract class DecoderAudioRenderer< try { audioSink.playToEndOfStream(); } catch (AudioSink.WriteException e) { - throw createRendererException(e, e.format, e.isRecoverable); + throw createRendererException( + e, e.format, e.isRecoverable, PlaybackException.ERROR_CODE_AUDIO_TRACK_WRITE_FAILED); } return; } @@ -278,7 +280,8 @@ public abstract class DecoderAudioRenderer< try { processEndOfStream(); } catch (AudioSink.WriteException e) { - throw createRendererException(e, /* format= */ null); + throw createRendererException( + e, /* format= */ null, PlaybackException.ERROR_CODE_AUDIO_TRACK_WRITE_FAILED); } return; } else { @@ -298,15 +301,19 @@ public abstract class DecoderAudioRenderer< while (feedInputBuffer()) {} TraceUtil.endSection(); } catch (DecoderException e) { + // Can happen with dequeueOutputBuffer, dequeueInputBuffer, queueInputBuffer Log.e(TAG, "Audio codec error", e); eventDispatcher.audioCodecError(e); - throw createRendererException(e, inputFormat); + throw createRendererException(e, inputFormat, PlaybackException.ERROR_CODE_DECODING_FAILED); } catch (AudioSink.ConfigurationException e) { - throw createRendererException(e, e.format); + throw createRendererException( + e, e.format, PlaybackException.ERROR_CODE_AUDIO_TRACK_INIT_FAILED); } catch (AudioSink.InitializationException e) { - throw createRendererException(e, e.format, e.isRecoverable); + throw createRendererException( + e, e.format, e.isRecoverable, PlaybackException.ERROR_CODE_AUDIO_TRACK_INIT_FAILED); } catch (AudioSink.WriteException e) { - throw createRendererException(e, e.format, e.isRecoverable); + throw createRendererException( + e, e.format, e.isRecoverable, PlaybackException.ERROR_CODE_AUDIO_TRACK_WRITE_FAILED); } decoderCounters.ensureUpdated(); } @@ -382,7 +389,8 @@ public abstract class DecoderAudioRenderer< try { processEndOfStream(); } catch (AudioSink.WriteException e) { - throw createRendererException(e, e.format, e.isRecoverable); + throw createRendererException( + e, e.format, e.isRecoverable, PlaybackException.ERROR_CODE_AUDIO_TRACK_WRITE_FAILED); } } return false; @@ -624,9 +632,11 @@ public abstract class DecoderAudioRenderer< } catch (DecoderException e) { Log.e(TAG, "Audio codec error", e); eventDispatcher.audioCodecError(e); - throw createRendererException(e, inputFormat); + throw createRendererException( + e, inputFormat, PlaybackException.ERROR_CODE_DECODER_INIT_FAILED); } catch (OutOfMemoryError e) { - throw createRendererException(e, inputFormat); + throw createRendererException( + e, inputFormat, PlaybackException.ERROR_CODE_DECODER_INIT_FAILED); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index 2fc8667bc5..0e3aa17212 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -34,6 +34,7 @@ import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlayerMessage.Target; import com.google.android.exoplayer2.RendererCapabilities; @@ -477,7 +478,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media try { audioSink.configure(audioSinkInputFormat, /* specifiedBufferSize= */ 0, channelMap); } catch (AudioSink.ConfigurationException e) { - throw createRendererException(e, e.format); + throw createRendererException( + e, e.format, PlaybackException.ERROR_CODE_AUDIO_TRACK_INIT_FAILED); } } @@ -636,9 +638,11 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media try { fullyConsumed = audioSink.handleBuffer(buffer, bufferPresentationTimeUs, sampleCount); } catch (InitializationException e) { - throw createRendererException(e, e.format, e.isRecoverable); + throw createRendererException( + e, e.format, e.isRecoverable, PlaybackException.ERROR_CODE_AUDIO_TRACK_INIT_FAILED); } catch (WriteException e) { - throw createRendererException(e, format, e.isRecoverable); + throw createRendererException( + e, format, e.isRecoverable, PlaybackException.ERROR_CODE_AUDIO_TRACK_WRITE_FAILED); } if (fullyConsumed) { @@ -657,7 +661,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media try { audioSink.playToEndOfStream(); } catch (AudioSink.WriteException e) { - throw createRendererException(e, e.format, e.isRecoverable); + throw createRendererException( + e, e.format, e.isRecoverable, PlaybackException.ERROR_CODE_AUDIO_TRACK_WRITE_FAILED); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index fdcfe848ae..988a5286f7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -49,6 +49,7 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer.InsufficientCapacityException; @@ -493,7 +494,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { try { return supportsFormat(mediaCodecSelector, format); } catch (DecoderQueryException e) { - throw createRendererException(e, format); + throw createRendererException(e, format, PlaybackException.ERROR_CODE_DECODER_QUERY_FAILED); } } @@ -592,7 +593,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer { try { maybeInitCodecWithFallback(mediaCrypto, mediaCryptoRequiresSecureDecoder); } catch (DecoderInitializationException e) { - throw createRendererException(e, inputFormat); + throw createRendererException( + e, inputFormat, PlaybackException.ERROR_CODE_DECODER_INIT_FAILED); } } @@ -848,7 +850,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer { releaseCodec(); } throw createRendererException( - createDecoderException(e, getCodecInfo()), inputFormat, isRecoverable); + createDecoderException(e, getCodecInfo()), + inputFormat, + isRecoverable, + PlaybackException.ERROR_CODE_DECODING_FAILED); } throw e; } @@ -1257,7 +1262,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer { return true; } else { throw createRendererException( - createDecoderException(e, getCodecInfo()), inputFormat, /* isRecoverable= */ false); + createDecoderException(e, getCodecInfo()), + inputFormat, + /* isRecoverable= */ false, + PlaybackException.ERROR_CODE_DECODING_FAILED); } } @@ -1442,7 +1450,11 @@ public abstract class MediaCodecRenderer extends BaseRenderer { if (newFormat.sampleMimeType == null) { // If the new format is invalid, it is either a media bug or it is not intended to be played. // See also https://github.com/google/ExoPlayer/issues/8283. - throw createRendererException(new IllegalArgumentException(), newFormat); + + throw createRendererException( + new IllegalArgumentException(), + newFormat, + PlaybackException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); } setSourceDrmSession(formatHolder.drmSession); inputFormat = newFormat; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/DecoderVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/DecoderVideoRenderer.java index d351442192..6628330338 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/DecoderVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/DecoderVideoRenderer.java @@ -34,6 +34,7 @@ import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.PlayerMessage.Target; import com.google.android.exoplayer2.decoder.Decoder; import com.google.android.exoplayer2.decoder.DecoderCounters; @@ -211,7 +212,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer { } catch (DecoderException e) { Log.e(TAG, "Video codec error", e); eventDispatcher.videoCodecError(e); - throw createRendererException(e, inputFormat); + throw createRendererException(e, inputFormat, PlaybackException.ERROR_CODE_DECODING_FAILED); } decoderCounters.ensureUpdated(); } @@ -691,9 +692,11 @@ public abstract class DecoderVideoRenderer extends BaseRenderer { } catch (DecoderException e) { Log.e(TAG, "Video codec error", e); eventDispatcher.videoCodecError(e); - throw createRendererException(e, inputFormat); + throw createRendererException( + e, inputFormat, PlaybackException.ERROR_CODE_DECODER_INIT_FAILED); } catch (OutOfMemoryError e) { - throw createRendererException(e, inputFormat); + throw createRendererException( + e, inputFormat, PlaybackException.ERROR_CODE_DECODER_INIT_FAILED); } }