diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationException.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationException.java index 03909481fb..524802aa02 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationException.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationException.java @@ -25,10 +25,12 @@ import android.os.SystemClock; import androidx.annotation.IntDef; import androidx.annotation.Nullable; import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.audio.AudioProcessor; import com.google.android.exoplayer2.audio.AudioProcessor.AudioFormat; import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.Util; +import com.google.common.collect.ImmutableBiMap; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -37,6 +39,167 @@ import java.lang.annotation.Target; /** Thrown when a non-locally recoverable transformation failure occurs. */ public final class TransformationException extends Exception { + /** + * Codes that identify causes of {@link Transformer} errors. + * + *
This list of errors may be extended in future versions. The underlying values may also + * change, so it is best to avoid relying on them directly without using the constants. + */ + // TODO(b/209469847): Update the javadoc once the underlying values are fixed. + @Documented + @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) + @IntDef( + open = true, + value = { + ERROR_CODE_UNSPECIFIED, + ERROR_CODE_FAILED_RUNTIME_CHECK, + ERROR_CODE_IO_UNSPECIFIED, + ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, + ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT, + ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE, + ERROR_CODE_IO_BAD_HTTP_STATUS, + ERROR_CODE_IO_FILE_NOT_FOUND, + ERROR_CODE_IO_NO_PERMISSION, + ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED, + ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE, + ERROR_CODE_DECODER_INIT_FAILED, + ERROR_CODE_DECODING_FAILED, + ERROR_CODE_DECODING_FORMAT_UNSUPPORTED, + ERROR_CODE_ENCODER_INIT_FAILED, + ERROR_CODE_ENCODING_FAILED, + ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED, + ERROR_CODE_GL_INIT_FAILED, + ERROR_CODE_GL_PROCESSING_FAILED, + ERROR_CODE_AUDIO_PROCESSOR_INIT_FAILED, + }) + public @interface ErrorCode {} + + // Miscellaneous errors (1xxx). + + /** Caused by an error whose cause could not be identified. */ + public static final int ERROR_CODE_UNSPECIFIED = 1000; + /** + * Caused by a failed runtime check. + * + *
This can happen when transformer reaches an invalid state. + */ + public static final int ERROR_CODE_FAILED_RUNTIME_CHECK = 1001; + + // Input/Output errors (2xxx). + + /** Caused by an Input/Output error which could not be identified. */ + public static final int ERROR_CODE_IO_UNSPECIFIED = 2000; + /** + * Caused by a network connection failure. + * + *
The following is a non-exhaustive list of possible reasons: + * + *
For example, this can happen when the player is expecting a piece of media, but the server
+ * returns a paywall HTML page, with content type "text/html".
+ */
+ public static final int ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE = 2003;
+ /** Caused by an HTTP server returning an unexpected HTTP response status code. */
+ public static final int ERROR_CODE_IO_BAD_HTTP_STATUS = 2004;
+ /** Caused by a non-existent file. */
+ public static final int ERROR_CODE_IO_FILE_NOT_FOUND = 2005;
+ /**
+ * Caused by lack of permission to perform an IO operation. For example, lack of permission to
+ * access internet or external storage.
+ */
+ public static final int ERROR_CODE_IO_NO_PERMISSION = 2006;
+ /**
+ * Caused by the player trying to access cleartext HTTP traffic (meaning http:// rather than
+ * https://) when the app's Network Security Configuration does not permit it.
+ */
+ public static final int ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED = 2007;
+ /** Caused by reading data out of the data bound. */
+ public static final int ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE = 2008;
+
+ // Decoding errors (3xxx).
+
+ /** Caused by a decoder initialization failure. */
+ public static final int ERROR_CODE_DECODER_INIT_FAILED = 3001;
+ /** Caused by a failure while trying to decode media samples. */
+ public static final int ERROR_CODE_DECODING_FAILED = 3002;
+ /** Caused by trying to decode content whose format is not supported. */
+ public static final int ERROR_CODE_DECODING_FORMAT_UNSUPPORTED = 3003;
+
+ // Encoding errors (4xxx).
+
+ /** Caused by an encoder initialization failure. */
+ public static final int ERROR_CODE_ENCODER_INIT_FAILED = 4001;
+ /** Caused by a failure while trying to encode media samples. */
+ public static final int ERROR_CODE_ENCODING_FAILED = 4002;
+ /** Caused by requesting to encode content in a format that is not supported by the device. */
+ public static final int ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED = 4003;
+
+ // Video editing errors (5xxx).
+
+ /** Caused by a GL initialization failure. */
+ public static final int ERROR_CODE_GL_INIT_FAILED = 5001;
+ /** Caused by a failure while using or releasing a GL program. */
+ public static final int ERROR_CODE_GL_PROCESSING_FAILED = 5002;
+
+ // Audio editing errors (6xxx).
+
+ /** Caused by an audio processor initialization failure. */
+ public static final int ERROR_CODE_AUDIO_PROCESSOR_INIT_FAILED = 6001;
+
+ private static final ImmutableBiMap If the exception is a runtime exception, error code {@link ERROR_CODE_FAILED_RUNTIME_CHECK}
- * is used. Otherwise, the created instance has error code {@link ERROR_CODE_UNSPECIFIED}.
+ * If the exception is a runtime exception, error code {@link #ERROR_CODE_FAILED_RUNTIME_CHECK}
+ * is used. Otherwise, the created instance has error code {@link #ERROR_CODE_UNSPECIFIED}.
*
* @param cause The cause of the failure.
* @return The created instance.
@@ -85,107 +248,17 @@ public final class TransformationException extends Exception {
}
/**
- * Codes that identify causes of {@link Transformer} errors.
+ * Converts a {@link PlaybackException} to a {@code TransformationException}.
*
- * This list of errors may be extended in future versions.
+ * If no corresponding error code exists, the created instance will have {@link
+ * #ERROR_CODE_UNSPECIFIED}.
*/
- @Documented
- @Retention(RetentionPolicy.SOURCE)
- @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
- @IntDef(
- open = true,
- value = {
- ERROR_CODE_UNSPECIFIED,
- ERROR_CODE_FAILED_RUNTIME_CHECK,
- ERROR_CODE_DECODER_INIT_FAILED,
- ERROR_CODE_DECODING_FAILED,
- ERROR_CODE_DECODING_FORMAT_UNSUPPORTED,
- ERROR_CODE_ENCODER_INIT_FAILED,
- ERROR_CODE_ENCODING_FAILED,
- ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED,
- ERROR_CODE_GL_INIT_FAILED,
- ERROR_CODE_GL_PROCESSING_FAILED,
- ERROR_CODE_AUDIO_PROCESSOR_INIT_FAILED,
- })
- public @interface ErrorCode {}
-
- // Miscellaneous errors (1xxx).
-
- /** Caused by an error whose cause could not be identified. */
- public static final int ERROR_CODE_UNSPECIFIED = 1000;
- /**
- * Caused by a failed runtime check.
- *
- * This can happen when transformer reaches an invalid state.
- */
- public static final int ERROR_CODE_FAILED_RUNTIME_CHECK = 1001;
-
- // Decoding errors (2xxx).
-
- /** Caused by a decoder initialization failure. */
- public static final int ERROR_CODE_DECODER_INIT_FAILED = 2001;
- /** Caused by a failure while trying to decode media samples. */
- public static final int ERROR_CODE_DECODING_FAILED = 2002;
- /** Caused by trying to decode content whose format is not supported. */
- public static final int ERROR_CODE_DECODING_FORMAT_UNSUPPORTED = 2003;
-
- // Encoding errors (3xxx).
-
- /** Caused by an encoder initialization failure. */
- public static final int ERROR_CODE_ENCODER_INIT_FAILED = 3001;
- /** Caused by a failure while trying to encode media samples. */
- public static final int ERROR_CODE_ENCODING_FAILED = 3002;
- /** Caused by requesting to encode content in a format that is not supported by the device. */
- public static final int ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED = 3003;
-
- // Video editing errors (4xxx).
-
- /** Caused by a GL initialization failure. */
- public static final int ERROR_CODE_GL_INIT_FAILED = 4001;
- /** Caused by a failure while using or releasing a GL program. */
- public static final int ERROR_CODE_GL_PROCESSING_FAILED = 4002;
-
- // Audio editing errors (5xxx).
-
- /** Caused by an audio processor initialization failure. */
- public static final int ERROR_CODE_AUDIO_PROCESSOR_INIT_FAILED = 5001;
-
- /** Returns the name of a given {@code errorCode}. */
- public static String getErrorCodeName(@ErrorCode int errorCode) {
- switch (errorCode) {
- case ERROR_CODE_UNSPECIFIED:
- return "ERROR_CODE_UNSPECIFIED";
- case ERROR_CODE_FAILED_RUNTIME_CHECK:
- return "ERROR_CODE_FAILED_RUNTIME_CHECK";
- case ERROR_CODE_DECODER_INIT_FAILED:
- return "ERROR_CODE_DECODER_INIT_FAILED";
- case ERROR_CODE_DECODING_FAILED:
- return "ERROR_CODE_DECODING_FAILED";
- case ERROR_CODE_DECODING_FORMAT_UNSUPPORTED:
- return "ERROR_CODE_DECODING_FORMAT_UNSUPPORTED";
- case ERROR_CODE_ENCODER_INIT_FAILED:
- return "ERROR_CODE_ENCODER_INIT_FAILED";
- case ERROR_CODE_ENCODING_FAILED:
- return "ERROR_CODE_ENCODING_FAILED";
- case ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED:
- return "ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED";
- case ERROR_CODE_GL_INIT_FAILED:
- return "ERROR_CODE_GL_INIT_FAILED";
- case ERROR_CODE_GL_PROCESSING_FAILED:
- return "ERROR_CODE_GL_PROCESSING_FAILED";
- case ERROR_CODE_AUDIO_PROCESSOR_INIT_FAILED:
- return "ERROR_CODE_AUDIO_PROCESSOR_INIT_FAILED";
- default:
- return "invalid error code";
- }
- }
-
- /**
- * Equivalent to {@link TransformationException#getErrorCodeName(int)
- * TransformationException.getErrorCodeName(this.errorCode)}.
- */
- public final String getErrorCodeName() {
- return getErrorCodeName(errorCode);
+ /* package */ static TransformationException createForPlaybackException(
+ PlaybackException exception) {
+ return new TransformationException(
+ exception.getMessage(),
+ exception.getCause(),
+ getErrorCodeForName(exception.getErrorCodeName()));
}
/** An error code which identifies the cause of the transformation failure. */
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java
index b1688ee62b..b30299a359 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java
@@ -845,7 +845,7 @@ public final class Transformer {
handleTransformationEnded(
cause instanceof TransformationException
? (TransformationException) cause
- : TransformationException.createForUnexpected(error));
+ : TransformationException.createForPlaybackException(error));
}
private void handleTransformationEnded(@Nullable TransformationException exception) {
diff --git a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTest.java b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTest.java
index 6bb8925bba..a72266330c 100644
--- a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTest.java
+++ b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTest.java
@@ -35,7 +35,6 @@ import android.view.Surface;
import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.testutil.DumpFileAsserts;
import com.google.android.exoplayer2.testutil.FakeClock;
@@ -295,15 +294,14 @@ public final class TransformerTest {
}
@Test
- public void startTransformation_withPlayerError_completesWithError() throws Exception {
+ public void startTransformation_withIoError_completesWithError() throws Exception {
Transformer transformer = new Transformer.Builder(context).setClock(clock).build();
MediaItem mediaItem = MediaItem.fromUri("asset:///non-existing-path.mp4");
transformer.startTransformation(mediaItem, outputPath);
TransformationException exception = TransformerTestRunner.runUntilError(transformer);
- assertThat(exception).hasCauseThat().isInstanceOf(ExoPlaybackException.class);
- assertThat(exception).hasCauseThat().hasCauseThat().isInstanceOf(IOException.class);
+ assertThat(exception).hasCauseThat().isInstanceOf(IOException.class);
}
@Test