Assign PlaybackException.ErrorCode to renderer failures.
PiperOrigin-RevId: 381852092
This commit is contained in:
parent
7aaba1ffe5
commit
ffbec2234d
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
|
@ -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.
|
||||
* <p>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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user