diff --git a/constants.gradle b/constants.gradle index 51e671fd2c..4037f925ad 100644 --- a/constants.gradle +++ b/constants.gradle @@ -32,6 +32,7 @@ project.ext { // Keep this in sync with Google's internal Checker Framework version. checkerframeworkVersion = '3.5.0' checkerframeworkCompatVersion = '2.5.0' + errorProneVersion = '2.9.0' jsr305Version = '3.0.2' kotlinAnnotationsVersion = '1.5.20' androidxAnnotationVersion = '1.2.0' diff --git a/library/common/build.gradle b/library/common/build.gradle index bdfe7a00f3..d4aa1615f8 100644 --- a/library/common/build.gradle +++ b/library/common/build.gradle @@ -27,6 +27,7 @@ dependencies { } implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion compileOnly 'com.google.code.findbugs:jsr305:' + jsr305Version + compileOnly 'com.google.errorprone:error_prone_annotations:' + errorProneVersion compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkCompatVersion compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.jetbrains.kotlin:kotlin-annotations-jvm:' + kotlinAnnotationsVersion diff --git a/library/common/src/main/java/com/google/android/exoplayer2/C.java b/library/common/src/main/java/com/google/android/exoplayer2/C.java index 44d9e0277c..975a0efd8f 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/C.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/C.java @@ -24,10 +24,10 @@ import android.media.MediaCrypto; import android.media.MediaFormat; import android.view.Surface; import androidx.annotation.IntDef; -import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; +import com.google.errorprone.annotations.InlineMe; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -1110,112 +1110,51 @@ public final class C { * audio MIME type. */ public static final int FORMAT_UNSUPPORTED_TYPE = 0b000; - /** - * Converts a time in microseconds to the corresponding time in milliseconds, preserving {@link - * #TIME_UNSET} and {@link #TIME_END_OF_SOURCE} values. - * - * @param timeUs The time in microseconds. - * @return The corresponding time in milliseconds. - */ + + /** @deprecated Use {@link Util#usToMs(long)}. */ + @InlineMe( + replacement = "Util.usToMs(timeUs)", + imports = {"com.google.android.exoplayer2.util.Util"}) + @Deprecated public static long usToMs(long timeUs) { - return (timeUs == TIME_UNSET || timeUs == TIME_END_OF_SOURCE) ? timeUs : (timeUs / 1000); + return Util.usToMs(timeUs); } - /** - * Converts a time in milliseconds to the corresponding time in microseconds, preserving {@link - * #TIME_UNSET} values and {@link #TIME_END_OF_SOURCE} values. - * - * @param timeMs The time in milliseconds. - * @return The corresponding time in microseconds. - */ + /** @deprecated Use {@link Util#msToUs(long)}. */ + @InlineMe( + replacement = "Util.msToUs(timeMs)", + imports = {"com.google.android.exoplayer2.util.Util"}) + @Deprecated public static long msToUs(long timeMs) { - return (timeMs == TIME_UNSET || timeMs == TIME_END_OF_SOURCE) ? timeMs : (timeMs * 1000); + return Util.msToUs(timeMs); } - /** - * Returns a newly generated audio session identifier, or {@link AudioManager#ERROR} if an error - * occurred in which case audio playback may fail. - * - * @see AudioManager#generateAudioSessionId() - */ + /** @deprecated Use {@link Util#generateAudioSessionIdV21(Context)}. */ + @InlineMe( + replacement = "Util.generateAudioSessionIdV21(context)", + imports = {"com.google.android.exoplayer2.util.Util"}) + @Deprecated @RequiresApi(21) public static int generateAudioSessionIdV21(Context context) { - @Nullable - AudioManager audioManager = ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE)); - return audioManager == null ? AudioManager.ERROR : audioManager.generateAudioSessionId(); + return Util.generateAudioSessionIdV21(context); } - /** - * Returns string representation of a {@link FormatSupport} flag. - * - * @param formatSupport A {@link FormatSupport} flag. - * @return A string representation of the flag. - */ + /** @deprecated Use {@link Util#getFormatSupportString(int)}. */ + @InlineMe( + replacement = "Util.getFormatSupportString(formatSupport)", + imports = {"com.google.android.exoplayer2.util.Util"}) + @Deprecated public static String getFormatSupportString(@FormatSupport int formatSupport) { - switch (formatSupport) { - case FORMAT_HANDLED: - return "YES"; - case FORMAT_EXCEEDS_CAPABILITIES: - return "NO_EXCEEDS_CAPABILITIES"; - case FORMAT_UNSUPPORTED_DRM: - return "NO_UNSUPPORTED_DRM"; - case FORMAT_UNSUPPORTED_SUBTYPE: - return "NO_UNSUPPORTED_TYPE"; - case FORMAT_UNSUPPORTED_TYPE: - return "NO"; - default: - throw new IllegalStateException(); - } + return Util.getFormatSupportString(formatSupport); } - // Copy of relevant error codes defined in MediaDrm.ErrorCodes from API 31. - // TODO (internal b/192337376): Remove once ExoPlayer depends on SDK 31. - private static final int ERROR_KEY_EXPIRED = 2; - private static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4; - private static final int ERROR_INSUFFICIENT_SECURITY = 7; - private static final int ERROR_FRAME_TOO_LARGE = 8; - private static final int ERROR_CERTIFICATE_MALFORMED = 10; - private static final int ERROR_INIT_DATA = 15; - private static final int ERROR_KEY_NOT_LOADED = 16; - private static final int ERROR_LICENSE_PARSE = 17; - private static final int ERROR_LICENSE_POLICY = 18; - private static final int ERROR_LICENSE_RELEASE = 19; - private static final int ERROR_LICENSE_REQUEST_REJECTED = 20; - private static final int ERROR_LICENSE_RESTORE = 21; - private static final int ERROR_LICENSE_STATE = 22; - private static final int ERROR_PROVISIONING_CERTIFICATE = 24; - private static final int ERROR_PROVISIONING_CONFIG = 25; - private static final int ERROR_PROVISIONING_PARSE = 26; - private static final int ERROR_PROVISIONING_REQUEST_REJECTED = 27; - private static final int ERROR_PROVISIONING_RETRY = 28; - + /** @deprecated Use {@link Util#getErrorCodeForMediaDrmErrorCode(int)}. */ + @InlineMe( + replacement = "Util.getErrorCodeForMediaDrmErrorCode(mediaDrmErrorCode)", + imports = {"com.google.android.exoplayer2.util.Util"}) + @Deprecated @PlaybackException.ErrorCode public static int getErrorCodeForMediaDrmErrorCode(int mediaDrmErrorCode) { - switch (mediaDrmErrorCode) { - case ERROR_PROVISIONING_CONFIG: - case ERROR_PROVISIONING_PARSE: - case ERROR_PROVISIONING_REQUEST_REJECTED: - case ERROR_PROVISIONING_CERTIFICATE: - case ERROR_PROVISIONING_RETRY: - return PlaybackException.ERROR_CODE_DRM_PROVISIONING_FAILED; - case ERROR_LICENSE_PARSE: - case ERROR_LICENSE_RELEASE: - case ERROR_LICENSE_REQUEST_REJECTED: - case ERROR_LICENSE_RESTORE: - case ERROR_LICENSE_STATE: - case ERROR_CERTIFICATE_MALFORMED: - return PlaybackException.ERROR_CODE_DRM_LICENSE_ACQUISITION_FAILED; - case ERROR_LICENSE_POLICY: - case ERROR_INSUFFICIENT_OUTPUT_PROTECTION: - case ERROR_INSUFFICIENT_SECURITY: - case ERROR_KEY_EXPIRED: - case ERROR_KEY_NOT_LOADED: - return PlaybackException.ERROR_CODE_DRM_DISALLOWED_OPERATION; - case ERROR_INIT_DATA: - case ERROR_FRAME_TOO_LARGE: - return PlaybackException.ERROR_CODE_DRM_CONTENT_ERROR; - default: - return PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR; - } + return Util.getErrorCodeForMediaDrmErrorCode(mediaDrmErrorCode); } } diff --git a/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java index 40d4b2e0a9..c152bd5d05 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -38,6 +38,8 @@ import android.database.sqlite.SQLiteDatabase; import android.graphics.Point; import android.hardware.display.DisplayManager; import android.media.AudioFormat; +import android.media.AudioManager; +import android.media.MediaDrm; import android.net.Uri; import android.os.Build; import android.os.Handler; @@ -60,6 +62,7 @@ import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.upstream.DataSource; import com.google.common.base.Ascii; import com.google.common.base.Charsets; @@ -1169,6 +1172,28 @@ public final class Util { return min; } + /** + * Converts a time in microseconds to the corresponding time in milliseconds, preserving {@link + * C#TIME_UNSET} and {@link C#TIME_END_OF_SOURCE} values. + * + * @param timeUs The time in microseconds. + * @return The corresponding time in milliseconds. + */ + public static long usToMs(long timeUs) { + return (timeUs == C.TIME_UNSET || timeUs == C.TIME_END_OF_SOURCE) ? timeUs : (timeUs / 1000); + } + + /** + * Converts a time in milliseconds to the corresponding time in microseconds, preserving {@link + * C#TIME_UNSET} values and {@link C#TIME_END_OF_SOURCE} values. + * + * @param timeMs The time in milliseconds. + * @return The corresponding time in microseconds. + */ + public static long msToUs(long timeMs) { + return (timeMs == C.TIME_UNSET || timeMs == C.TIME_END_OF_SOURCE) ? timeMs : (timeMs * 1000); + } + /** * Parses an xs:duration attribute value, returning the parsed duration in milliseconds. * @@ -1755,6 +1780,19 @@ public final class Util { } } + /** + * Returns a newly generated audio session identifier, or {@link AudioManager#ERROR} if an error + * occurred in which case audio playback may fail. + * + * @see AudioManager#generateAudioSessionId() + */ + @RequiresApi(21) + public static int generateAudioSessionIdV21(Context context) { + @Nullable + AudioManager audioManager = ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE)); + return audioManager == null ? AudioManager.ERROR : audioManager.generateAudioSessionId(); + } + /** * Derives a DRM {@link UUID} from {@code drmScheme}. * @@ -1779,6 +1817,41 @@ public final class Util { } } + /** + * Returns a {@link PlaybackException.ErrorCode} value that corresponds to the provided {@link + * MediaDrm.ErrorCodes} value. Returns {@link PlaybackException#ERROR_CODE_DRM_SYSTEM_ERROR} if + * the provided error code isn't recognised. + */ + @PlaybackException.ErrorCode + public static int getErrorCodeForMediaDrmErrorCode(int mediaDrmErrorCode) { + switch (mediaDrmErrorCode) { + case MediaDrm.ErrorCodes.ERROR_PROVISIONING_CONFIG: + case MediaDrm.ErrorCodes.ERROR_PROVISIONING_PARSE: + case MediaDrm.ErrorCodes.ERROR_PROVISIONING_REQUEST_REJECTED: + case MediaDrm.ErrorCodes.ERROR_PROVISIONING_CERTIFICATE: + case MediaDrm.ErrorCodes.ERROR_PROVISIONING_RETRY: + return PlaybackException.ERROR_CODE_DRM_PROVISIONING_FAILED; + case MediaDrm.ErrorCodes.ERROR_LICENSE_PARSE: + case MediaDrm.ErrorCodes.ERROR_LICENSE_RELEASE: + case MediaDrm.ErrorCodes.ERROR_LICENSE_REQUEST_REJECTED: + case MediaDrm.ErrorCodes.ERROR_LICENSE_RESTORE: + case MediaDrm.ErrorCodes.ERROR_LICENSE_STATE: + case MediaDrm.ErrorCodes.ERROR_CERTIFICATE_MALFORMED: + return PlaybackException.ERROR_CODE_DRM_LICENSE_ACQUISITION_FAILED; + case MediaDrm.ErrorCodes.ERROR_LICENSE_POLICY: + case MediaDrm.ErrorCodes.ERROR_INSUFFICIENT_OUTPUT_PROTECTION: + case MediaDrm.ErrorCodes.ERROR_INSUFFICIENT_SECURITY: + case MediaDrm.ErrorCodes.ERROR_KEY_EXPIRED: + case MediaDrm.ErrorCodes.ERROR_KEY_NOT_LOADED: + return PlaybackException.ERROR_CODE_DRM_DISALLOWED_OPERATION; + case MediaDrm.ErrorCodes.ERROR_INIT_DATA: + case MediaDrm.ErrorCodes.ERROR_FRAME_TOO_LARGE: + return PlaybackException.ERROR_CODE_DRM_CONTENT_ERROR; + default: + return PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR; + } + } + /** * Makes a best guess to infer the {@link ContentType} from a {@link Uri}. * @@ -2428,6 +2501,29 @@ public final class Util { } } + /** + * Returns string representation of a {@link C.FormatSupport} flag. + * + * @param formatSupport A {@link C.FormatSupport} flag. + * @return A string representation of the flag. + */ + public static String getFormatSupportString(@C.FormatSupport int formatSupport) { + switch (formatSupport) { + case C.FORMAT_HANDLED: + return "YES"; + case C.FORMAT_EXCEEDS_CAPABILITIES: + return "NO_EXCEEDS_CAPABILITIES"; + case C.FORMAT_UNSUPPORTED_DRM: + return "NO_UNSUPPORTED_DRM"; + case C.FORMAT_UNSUPPORTED_SUBTYPE: + return "NO_UNSUPPORTED_TYPE"; + case C.FORMAT_UNSUPPORTED_TYPE: + return "NO"; + default: + throw new IllegalStateException(); + } + } + @Nullable private static String getSystemProperty(String name) { try { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index 62b5347ece..2d82609c74 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -1047,8 +1047,8 @@ public interface ExoPlayer extends Player { /** * Sets the ID of the audio session to attach to the underlying {@link android.media.AudioTrack}. * - *

The audio session ID can be generated using {@link C#generateAudioSessionIdV21(Context)} for - * API 21+. + *

The audio session ID can be generated using {@link Util#generateAudioSessionIdV21(Context)} + * for API 21+. * * @param audioSessionId The audio session ID, or {@link C#AUDIO_SESSION_ID_UNSET} if it should be * generated by the framework.