Compare commits

...

13 Commits

Author SHA1 Message Date
kimvde
4d68243158 Only join video graph output in playlist mode.
DefaultVideoSink.join() was called when join() was called on the
InputVideoSink. This makes sense in playlist mode but we shouldn't
join if the VideoGraph output is considered as a single clip.

This change is no-op. Indeed, for CompositionPlayer, the
allowedJoiningTimeMs is set to 0, so that join doesn't have any effect.

PiperOrigin-RevId: 750238085
2025-04-22 10:15:18 -07:00
kimvde
fe10ca2c9a Start and stop video rendering from CompositionPlayer
Before, we were starting and stopping video rendering when the
renderers were started/stopped. This doesn't work for multi-video
sequences though because we shouldn't stop and start rendering at every
MediaItem transition in any of the input sequences.

PiperOrigin-RevId: 750206410
2025-04-22 08:43:21 -07:00
jbibik
ab6b0f6e10 [ui-compose] Eliminated race condition inside button state
A bug was introduced because it was unclear that button state creation and listener registration were not an atomic operation. This happens because the `LaunchedEffect` which starts the listen-to-Player-Events coroutine can be pre-empted with other side effects, including the ones that change something in the Player.

`remember*State` functions create some button state object and initialise it with the correct fresh values pulled out of the Player. The subscription to Player events with a registration of a Listener(via `*ButtonState.observe()`) is not immediate. It *returns* immediately, but is instead scheduled to happen *later*, although within the same Handler message. Other LaunchedEffects could have been scheduled earlier and could take place between the button state creation and listener subscription.

This is not a problem if no changes to the player happen, but if we miss the *relevant* player events, we might end up with a UI that is out of sync with reality (e.g. button enabled/disabled when it should be flipped, icons toggled the wrong way). The way to fix this is to pull the latest values out of the Player on demand upon starting to listen to Player events.

PiperOrigin-RevId: 750183793
2025-04-22 07:31:19 -07:00
tonihei
1c855a8abf Remove unneeded SDK checks
PiperOrigin-RevId: 750172684
2025-04-22 06:48:41 -07:00
Copybara-Service
661effcddd Merge pull request #2323 from DolbyLaboratories:dlb/ac4-profile/dev
PiperOrigin-RevId: 750171380
2025-04-22 06:43:36 -07:00
michaelkatz
d3328456a7 Allow trailing whitespace in RTSP SessionDescription lines
This CL fixes the parser for the RTSP SessionDescription such that it will not choke if there is trailing whitespace in the lines.

PiperOrigin-RevId: 750158624
2025-04-22 05:53:56 -07:00
kimvde
ba97999657 Fix compilation error
Patterns in instanceof are not supported on Java 8.

PiperOrigin-RevId: 750147834
2025-04-22 05:12:58 -07:00
Copybara-Service
4d9f47920a Merge pull request #2285 from MGaetan89:deprecate_util_sdkint
PiperOrigin-RevId: 750142132
2025-04-22 04:53:39 -07:00
tonihei
ea837aa718 Remove release notes
Deprecatations don't need to be noted
2025-04-17 16:02:33 +01:00
Gaëtan Muller
340264e376 Update release notes 2025-04-17 15:59:01 +01:00
Gaëtan Muller
9b2e1cfca0 Deprecate Util.SDK_INT in favor of Build.VERSION.SDK_INT
`Util.SDK_INT` was introduced to be able to simulate any SDK version during tests.
This is possible by using Robolectric's `@Config(sdk)` annotation.
All usages of `Util.SDK_INT` have been replaced by `Build.VERSION.SDK_INT`.

This is a similar change to what was done in #2107.
2025-04-17 15:55:23 +01:00
ybai001
2500d91848 Add KEY_PROFILE, KEY_LEVEL support for AC-4 2025-04-10 09:39:23 +08:00
ybai001
28feb7bab5
Merge pull request #17 from androidx/main
Merge from androidx/main
2025-04-02 11:31:17 +08:00
217 changed files with 1049 additions and 604 deletions

View File

@ -54,6 +54,11 @@
connected to a legacy `MediaBrowserServiceCompat` produced a connected to a legacy `MediaBrowserServiceCompat` produced a
`NullPointerException`. `NullPointerException`.
* UI: * UI:
* Fix a Compose bug which resulted in a gap between setting the initial
button states and observing the change in state (e.g. icon shapes or
being enabled). Any changes made to the Player outside of the
observation period are now picked up
([#2313](https://github.com/androidx/media/issues/2313)).
* Downloads: * Downloads:
* Add partial download support for progressive streams. Apps can prepare a * Add partial download support for progressive streams. Apps can prepare a
progressive stream with `DownloadHelper`, and request a progressive stream with `DownloadHelper`, and request a
@ -73,6 +78,9 @@
* DASH extension: * DASH extension:
* Smooth Streaming extension: * Smooth Streaming extension:
* RTSP extension: * RTSP extension:
* Add parsing support for SessionDescriptions containing lines with
trailing whitespace characters
([#2357](https://github.com/androidx/media/issues/2357)).
* Decoder extensions (FFmpeg, VP9, AV1, etc.): * Decoder extensions (FFmpeg, VP9, AV1, etc.):
* MIDI extension: * MIDI extension:
* Leanback extension: * Leanback extension:

View File

@ -16,7 +16,7 @@
package androidx.media3.demo.composition; package androidx.media3.demo.composition;
import static android.content.pm.ActivityInfo.COLOR_MODE_HDR; import static android.content.pm.ActivityInfo.COLOR_MODE_HDR;
import static androidx.media3.common.util.Util.SDK_INT; import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.transformer.Composition.HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR; import static androidx.media3.transformer.Composition.HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR;
import static androidx.media3.transformer.Composition.HDR_MODE_KEEP_HDR; import static androidx.media3.transformer.Composition.HDR_MODE_KEEP_HDR;
import static androidx.media3.transformer.Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC; import static androidx.media3.transformer.Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC;

View File

@ -17,6 +17,7 @@ package androidx.media3.demo.effect
import android.Manifest import android.Manifest
import android.net.Uri import android.net.Uri
import android.os.Build.VERSION.SDK_INT
import android.os.Bundle import android.os.Bundle
import android.text.Spannable import android.text.Spannable
import android.text.SpannableString import android.text.SpannableString
@ -81,7 +82,6 @@ import androidx.lifecycle.lifecycleScope
import androidx.media3.common.Effect import androidx.media3.common.Effect
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.common.util.Util.SDK_INT
import androidx.media3.effect.Contrast import androidx.media3.effect.Contrast
import androidx.media3.effect.OverlayEffect import androidx.media3.effect.OverlayEffect
import androidx.media3.effect.StaticOverlaySettings import androidx.media3.effect.StaticOverlaySettings

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.demo.gl; package androidx.media3.demo.gl;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import android.app.Activity; import android.app.Activity;
@ -94,7 +95,7 @@ public final class MainActivity extends Activity {
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
if (Util.SDK_INT > 23) { if (SDK_INT > 23) {
initializePlayer(); initializePlayer();
if (playerView != null) { if (playerView != null) {
playerView.onResume(); playerView.onResume();
@ -105,7 +106,7 @@ public final class MainActivity extends Activity {
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
if (Util.SDK_INT <= 23 || player == null) { if (SDK_INT <= 23 || player == null) {
initializePlayer(); initializePlayer();
if (playerView != null) { if (playerView != null) {
playerView.onResume(); playerView.onResume();
@ -116,7 +117,7 @@ public final class MainActivity extends Activity {
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
if (Util.SDK_INT <= 23) { if (SDK_INT <= 23) {
if (playerView != null) { if (playerView != null) {
playerView.onPause(); playerView.onPause();
} }
@ -127,7 +128,7 @@ public final class MainActivity extends Activity {
@Override @Override
public void onStop() { public void onStop() {
super.onStop(); super.onStop();
if (Util.SDK_INT > 23) { if (SDK_INT > 23) {
if (playerView != null) { if (playerView != null) {
playerView.onPause(); playerView.onPause();
} }

View File

@ -17,8 +17,8 @@ package androidx.media3.demo.transformer;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.READ_MEDIA_VIDEO; import static android.Manifest.permission.READ_MEDIA_VIDEO;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Util.SDK_INT;
import static androidx.media3.transformer.Composition.HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR; import static androidx.media3.transformer.Composition.HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR;
import static androidx.media3.transformer.Composition.HDR_MODE_KEEP_HDR; import static androidx.media3.transformer.Composition.HDR_MODE_KEEP_HDR;
import static androidx.media3.transformer.Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC; import static androidx.media3.transformer.Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC;

View File

@ -16,6 +16,7 @@
package androidx.media3.demo.transformer; package androidx.media3.demo.transformer;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.exoplayer.DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS; import static androidx.media3.exoplayer.DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS;
@ -985,14 +986,14 @@ public final class TransformerActivity extends AppCompatActivity {
.setOngoing(true) .setOngoing(true)
.setSmallIcon(R.drawable.exo_icon_play) .setSmallIcon(R.drawable.exo_icon_play)
.build(); .build();
if (Util.SDK_INT >= 26) { if (SDK_INT >= 26) {
NotificationChannel channel = NotificationChannel channel =
new NotificationChannel( new NotificationChannel(
CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH); CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
NotificationManager manager = getSystemService(NotificationManager.class); NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel); manager.createNotificationChannel(channel);
} }
if (Util.SDK_INT >= 29) { if (SDK_INT >= 29) {
startForeground(NOTIFICATION_ID, notification, FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION); startForeground(NOTIFICATION_ID, notification, FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);
} else { } else {
startForeground(NOTIFICATION_ID, notification); startForeground(NOTIFICATION_ID, notification);

View File

@ -15,9 +15,9 @@
*/ */
package androidx.media3.cast; package androidx.media3.cast;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Util.SDK_INT;
import static androidx.media3.common.util.Util.castNonNull; import static androidx.media3.common.util.Util.castNonNull;
import static java.lang.Math.min; import static java.lang.Math.min;

View File

@ -15,6 +15,8 @@
*/ */
package androidx.media3.common; package androidx.media3.common;
import static android.os.Build.VERSION.SDK_INT;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
@ -45,10 +47,10 @@ public final class AudioAttributes {
.setContentType(audioAttributes.contentType) .setContentType(audioAttributes.contentType)
.setFlags(audioAttributes.flags) .setFlags(audioAttributes.flags)
.setUsage(audioAttributes.usage); .setUsage(audioAttributes.usage);
if (Util.SDK_INT >= 29) { if (SDK_INT >= 29) {
Api29.setAllowedCapturePolicy(builder, audioAttributes.allowedCapturePolicy); Api29.setAllowedCapturePolicy(builder, audioAttributes.allowedCapturePolicy);
} }
if (Util.SDK_INT >= 32) { if (SDK_INT >= 32) {
Api32.setSpatializationBehavior(builder, audioAttributes.spatializationBehavior); Api32.setSpatializationBehavior(builder, audioAttributes.spatializationBehavior);
} }
this.audioAttributes = builder.build(); this.audioAttributes = builder.build();

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.common; package androidx.media3.common;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import android.os.Binder; import android.os.Binder;
@ -25,7 +26,6 @@ import android.os.RemoteException;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.List; import java.util.List;
@ -56,7 +56,7 @@ public final class BundleListRetriever extends Binder {
// Soft limit of an IPC buffer size // Soft limit of an IPC buffer size
private static final int SUGGESTED_MAX_IPC_SIZE = private static final int SUGGESTED_MAX_IPC_SIZE =
Util.SDK_INT >= 30 ? IBinder.getSuggestedMaxIpcSizeBytes() : 64 * 1024; SDK_INT >= 30 ? IBinder.getSuggestedMaxIpcSizeBytes() : 64 * 1024;
private static final int REPLY_END_OF_LIST = 0; private static final int REPLY_END_OF_LIST = 0;
private static final int REPLY_CONTINUE = 1; private static final int REPLY_CONTINUE = 1;

View File

@ -15,13 +15,13 @@
*/ */
package androidx.media3.common; package androidx.media3.common;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkIndex; import static androidx.media3.common.util.Assertions.checkIndex;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import android.util.SparseBooleanArray; import android.util.SparseBooleanArray;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
/** /**
@ -222,7 +222,7 @@ public final class FlagSet {
return false; return false;
} }
FlagSet that = (FlagSet) o; FlagSet that = (FlagSet) o;
if (Util.SDK_INT < 24) { if (SDK_INT < 24) {
// SparseBooleanArray.equals() is not implemented on API levels below 24. // SparseBooleanArray.equals() is not implemented on API levels below 24.
if (size() != that.size()) { if (size() != that.size()) {
return false; return false;
@ -240,7 +240,7 @@ public final class FlagSet {
@Override @Override
public int hashCode() { public int hashCode() {
if (Util.SDK_INT < 24) { if (SDK_INT < 24) {
// SparseBooleanArray.hashCode() is not implemented on API levels below 24. // SparseBooleanArray.hashCode() is not implemented on API levels below 24.
int hashCode = size(); int hashCode = size();
for (int i = 0; i < size(); i++) { for (int i = 0; i < size(); i++) {

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.common.audio; package androidx.media3.common.audio;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
@ -55,7 +56,7 @@ public final class AudioFocusRequestCompat {
this.audioAttributes = audioFocusRequestCompat; this.audioAttributes = audioFocusRequestCompat;
this.pauseOnDuck = pauseOnDuck; this.pauseOnDuck = pauseOnDuck;
if (Util.SDK_INT < 26) { if (SDK_INT < 26) {
this.onAudioFocusChangeListener = this.onAudioFocusChangeListener =
new OnAudioFocusChangeListenerHandlerCompat( new OnAudioFocusChangeListenerHandlerCompat(
onAudioFocusChangeListener, focusChangeHandler); onAudioFocusChangeListener, focusChangeHandler);
@ -63,7 +64,7 @@ public final class AudioFocusRequestCompat {
this.onAudioFocusChangeListener = onAudioFocusChangeListener; this.onAudioFocusChangeListener = onAudioFocusChangeListener;
} }
if (Util.SDK_INT >= 26) { if (SDK_INT >= 26) {
this.frameworkAudioFocusRequest = this.frameworkAudioFocusRequest =
new AudioFocusRequest.Builder(focusGain) new AudioFocusRequest.Builder(focusGain)
.setAudioAttributes(audioAttributes.getAudioAttributesV21().audioAttributes) .setAudioAttributes(audioAttributes.getAudioAttributesV21().audioAttributes)

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.common.audio; package androidx.media3.common.audio;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.ElementType.TYPE_USE;
@ -29,7 +30,6 @@ import androidx.media3.common.util.BackgroundExecutor;
import androidx.media3.common.util.ConditionVariable; import androidx.media3.common.util.ConditionVariable;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -154,7 +154,7 @@ public final class AudioManagerCompat {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public static int requestAudioFocus( public static int requestAudioFocus(
AudioManager audioManager, AudioFocusRequestCompat focusRequest) { AudioManager audioManager, AudioFocusRequestCompat focusRequest) {
if (Util.SDK_INT >= 26) { if (SDK_INT >= 26) {
return audioManager.requestAudioFocus(focusRequest.getAudioFocusRequest()); return audioManager.requestAudioFocus(focusRequest.getAudioFocusRequest());
} else { } else {
return audioManager.requestAudioFocus( return audioManager.requestAudioFocus(
@ -176,7 +176,7 @@ public final class AudioManagerCompat {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public static int abandonAudioFocusRequest( public static int abandonAudioFocusRequest(
AudioManager audioManager, AudioFocusRequestCompat focusRequest) { AudioManager audioManager, AudioFocusRequestCompat focusRequest) {
if (Util.SDK_INT >= 26) { if (SDK_INT >= 26) {
return audioManager.abandonAudioFocusRequest(focusRequest.getAudioFocusRequest()); return audioManager.abandonAudioFocusRequest(focusRequest.getAudioFocusRequest());
} else { } else {
return audioManager.abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener()); return audioManager.abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener());
@ -204,7 +204,7 @@ public final class AudioManagerCompat {
*/ */
@IntRange(from = 0) @IntRange(from = 0)
public static int getStreamMinVolume(AudioManager audioManager, @C.StreamType int streamType) { public static int getStreamMinVolume(AudioManager audioManager, @C.StreamType int streamType) {
return Util.SDK_INT >= 28 ? audioManager.getStreamMinVolume(streamType) : 0; return SDK_INT >= 28 ? audioManager.getStreamMinVolume(streamType) : 0;
} }
/** /**
@ -233,7 +233,7 @@ public final class AudioManagerCompat {
* @return Whether the stream is muted. * @return Whether the stream is muted.
*/ */
public static boolean isStreamMute(AudioManager audioManager, @C.StreamType int streamType) { public static boolean isStreamMute(AudioManager audioManager, @C.StreamType int streamType) {
if (Util.SDK_INT >= 23) { if (SDK_INT >= 23) {
return audioManager.isStreamMute(streamType); return audioManager.isStreamMute(streamType);
} else { } else {
return getStreamVolume(audioManager, streamType) == 0; return getStreamVolume(audioManager, streamType) == 0;

View File

@ -62,6 +62,8 @@ public final class CodecSpecificDataUtil {
private static final String CODEC_ID_AV01 = "av01"; private static final String CODEC_ID_AV01 = "av01";
// MP4A AAC. // MP4A AAC.
private static final String CODEC_ID_MP4A = "mp4a"; private static final String CODEC_ID_MP4A = "mp4a";
// AC-4
private static final String CODEC_ID_AC4 = "ac-4";
private static final Pattern PROFILE_PATTERN = Pattern.compile("^\\D?(\\d+)$"); private static final Pattern PROFILE_PATTERN = Pattern.compile("^\\D?(\\d+)$");
@ -350,6 +352,8 @@ public final class CodecSpecificDataUtil {
return getAv1ProfileAndLevel(format.codecs, parts, format.colorInfo); return getAv1ProfileAndLevel(format.codecs, parts, format.colorInfo);
case CODEC_ID_MP4A: case CODEC_ID_MP4A:
return getAacCodecProfileAndLevel(format.codecs, parts); return getAacCodecProfileAndLevel(format.codecs, parts);
case CODEC_ID_AC4:
return getAc4CodecProfileAndLevel(format.codecs, parts);
default: default:
return null; return null;
} }
@ -763,6 +767,41 @@ public final class CodecSpecificDataUtil {
return null; return null;
} }
@Nullable
private static Pair<Integer, Integer> getAc4CodecProfileAndLevel(String codec, String[] parts) {
if (parts.length != 4) {
Log.w(TAG, "Ignoring malformed AC-4 codec string: " + codec);
return null;
}
int bitstreamVersionInteger;
int presentationVersionInteger;
int levelInteger;
try {
bitstreamVersionInteger = Integer.parseInt(parts[1]);
presentationVersionInteger = Integer.parseInt(parts[2]);
levelInteger = Integer.parseInt(parts[3]);
} catch (NumberFormatException e) {
Log.w(TAG, "Ignoring malformed AC-4 codec string: " + codec);
return null;
}
int profile =
ac4BitstreamAndPresentationVersionsToProfileConst(
bitstreamVersionInteger, presentationVersionInteger);
if (profile == -1) {
Log.w(
TAG,
"Unknown AC-4 profile: " + bitstreamVersionInteger + "." + presentationVersionInteger);
return null;
}
int level = ac4LevelNumberToConst(levelInteger);
if (level == -1) {
Log.w(TAG, "Unknown AC-4 level: " + levelInteger);
return null;
}
return new Pair<>(profile, level);
}
private static int avcProfileNumberToConst(int profileNumber) { private static int avcProfileNumberToConst(int profileNumber) {
switch (profileNumber) { switch (profileNumber) {
case 66: case 66:
@ -1094,5 +1133,51 @@ public final class CodecSpecificDataUtil {
} }
} }
private static int ac4BitstreamAndPresentationVersionsToProfileConst(
int bitstreamVersionInteger, int presentationVersionInteger) {
int ac4Profile = -1;
switch (bitstreamVersionInteger) {
case 0:
if (presentationVersionInteger == 0) {
ac4Profile = MediaCodecInfo.CodecProfileLevel.AC4Profile00;
}
break;
case 1:
if (presentationVersionInteger == 0) {
ac4Profile = MediaCodecInfo.CodecProfileLevel.AC4Profile10;
} else if (presentationVersionInteger == 1) {
ac4Profile = MediaCodecInfo.CodecProfileLevel.AC4Profile11;
}
break;
case 2:
if (presentationVersionInteger == 1) {
ac4Profile = MediaCodecInfo.CodecProfileLevel.AC4Profile21;
} else if (presentationVersionInteger == 2) {
ac4Profile = MediaCodecInfo.CodecProfileLevel.AC4Profile22;
}
break;
default:
break;
}
return ac4Profile;
}
private static int ac4LevelNumberToConst(int levelNumber) {
switch (levelNumber) {
case 0:
return MediaCodecInfo.CodecProfileLevel.AC4Level0;
case 1:
return MediaCodecInfo.CodecProfileLevel.AC4Level1;
case 2:
return MediaCodecInfo.CodecProfileLevel.AC4Level2;
case 3:
return MediaCodecInfo.CodecProfileLevel.AC4Level3;
case 4:
return MediaCodecInfo.CodecProfileLevel.AC4Level4;
default:
return -1;
}
}
private CodecSpecificDataUtil() {} private CodecSpecificDataUtil() {}
} }

View File

@ -17,6 +17,7 @@ package androidx.media3.common.util;
import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION; import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION;
import static android.opengl.GLU.gluErrorString; import static android.opengl.GLU.gluErrorString;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
@ -169,18 +170,17 @@ public final class GlUtil {
* <p>If {@code true}, the device supports a protected output path for DRM content when using GL. * <p>If {@code true}, the device supports a protected output path for DRM content when using GL.
*/ */
public static boolean isProtectedContentExtensionSupported(Context context) { public static boolean isProtectedContentExtensionSupported(Context context) {
if (Util.SDK_INT < 24) { if (SDK_INT < 24) {
return false; return false;
} }
if (Util.SDK_INT < 26 if (SDK_INT < 26 && ("samsung".equals(Build.MANUFACTURER) || "XT1650".equals(Build.MODEL))) {
&& ("samsung".equals(Build.MANUFACTURER) || "XT1650".equals(Build.MODEL))) {
// Samsung devices running Nougat are known to be broken. See // Samsung devices running Nougat are known to be broken. See
// https://github.com/google/ExoPlayer/issues/3373 and [Internal: b/37197802]. // https://github.com/google/ExoPlayer/issues/3373 and [Internal: b/37197802].
// Moto Z XT1650 is also affected. See // Moto Z XT1650 is also affected. See
// https://github.com/google/ExoPlayer/issues/3215. // https://github.com/google/ExoPlayer/issues/3215.
return false; return false;
} }
if (Util.SDK_INT < 26 if (SDK_INT < 26
&& !context && !context
.getPackageManager() .getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) { .hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
@ -242,7 +242,7 @@ public final class GlUtil {
public static boolean isBt2020PqExtensionSupported() { public static boolean isBt2020PqExtensionSupported() {
// On API<33, the system cannot display PQ content correctly regardless of whether BT2020 PQ // On API<33, the system cannot display PQ content correctly regardless of whether BT2020 PQ
// GL extension is supported. Context: http://b/252537203#comment5. // GL extension is supported. Context: http://b/252537203#comment5.
return Util.SDK_INT >= 33 && isExtensionSupported(EXTENSION_COLORSPACE_BT2020_PQ); return SDK_INT >= 33 && isExtensionSupported(EXTENSION_COLORSPACE_BT2020_PQ);
} }
/** Returns whether {@link #EXTENSION_COLORSPACE_BT2020_HLG} is supported. */ /** Returns whether {@link #EXTENSION_COLORSPACE_BT2020_HLG} is supported. */

View File

@ -15,7 +15,7 @@
*/ */
package androidx.media3.common.util; package androidx.media3.common.util;
import static androidx.media3.common.util.Util.SDK_INT; import static android.os.Build.VERSION.SDK_INT;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.media.AudioFormat; import android.media.AudioFormat;

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.common.util; package androidx.media3.common.util;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
@ -159,7 +160,7 @@ public final class NetworkTypeObserver {
private void handleConnectivityActionBroadcast(Context context) { private void handleConnectivityActionBroadcast(Context context) {
@C.NetworkType int networkType = getNetworkTypeFromConnectivityManager(context); @C.NetworkType int networkType = getNetworkTypeFromConnectivityManager(context);
if (Util.SDK_INT >= 31 && networkType == C.NETWORK_TYPE_4G) { if (SDK_INT >= 31 && networkType == C.NETWORK_TYPE_4G) {
// Delay update of the network type to check whether this is actually 5G-NSA. // Delay update of the network type to check whether this is actually 5G-NSA.
Api31.disambiguate4gAnd5gNsa(context, /* instance= */ NetworkTypeObserver.this); Api31.disambiguate4gAnd5gNsa(context, /* instance= */ NetworkTypeObserver.this);
} else { } else {
@ -239,7 +240,7 @@ public final class NetworkTypeObserver {
case TelephonyManager.NETWORK_TYPE_LTE: case TelephonyManager.NETWORK_TYPE_LTE:
return C.NETWORK_TYPE_4G; return C.NETWORK_TYPE_4G;
case TelephonyManager.NETWORK_TYPE_NR: case TelephonyManager.NETWORK_TYPE_NR:
return Util.SDK_INT >= 29 ? C.NETWORK_TYPE_5G_SA : C.NETWORK_TYPE_UNKNOWN; return SDK_INT >= 29 ? C.NETWORK_TYPE_5G_SA : C.NETWORK_TYPE_UNKNOWN;
case TelephonyManager.NETWORK_TYPE_IWLAN: case TelephonyManager.NETWORK_TYPE_IWLAN:
return C.NETWORK_TYPE_WIFI; return C.NETWORK_TYPE_WIFI;
case TelephonyManager.NETWORK_TYPE_GSM: case TelephonyManager.NETWORK_TYPE_GSM:

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.common.util; package androidx.media3.common.util;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.ElementType.TYPE_USE;
@ -113,7 +114,7 @@ public final class NotificationUtil {
@StringRes int nameResourceId, @StringRes int nameResourceId,
@StringRes int descriptionResourceId, @StringRes int descriptionResourceId,
@Importance int importance) { @Importance int importance) {
if (Util.SDK_INT >= 26) { if (SDK_INT >= 26) {
NotificationManager notificationManager = NotificationManager notificationManager =
checkNotNull( checkNotNull(
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)); (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE));

View File

@ -155,10 +155,9 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
public final class Util { public final class Util {
/** /**
* Like {@link Build.VERSION#SDK_INT}, but in a place where it can be conveniently overridden for * @deprecated Use {@link Build.VERSION#SDK_INT} instead.
* local testing.
*/ */
@UnstableApi public static final int SDK_INT = Build.VERSION.SDK_INT; @UnstableApi @Deprecated public static final int SDK_INT = Build.VERSION.SDK_INT;
/** /**
* @deprecated Use {@link Build#DEVICE} instead. * @deprecated Use {@link Build#DEVICE} instead.
@ -178,7 +177,7 @@ public final class Util {
/** A concise description of the device that it can be useful to log for debugging purposes. */ /** A concise description of the device that it can be useful to log for debugging purposes. */
@UnstableApi @UnstableApi
public static final String DEVICE_DEBUG_INFO = public static final String DEVICE_DEBUG_INFO =
Build.DEVICE + ", " + Build.MODEL + ", " + Build.MANUFACTURER + ", " + SDK_INT; Build.DEVICE + ", " + Build.MODEL + ", " + Build.MANUFACTURER + ", " + Build.VERSION.SDK_INT;
/** An empty byte array. */ /** An empty byte array. */
@UnstableApi public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; @UnstableApi public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
@ -249,7 +248,7 @@ public final class Util {
/** /**
* Registers a {@link BroadcastReceiver} that's not intended to receive broadcasts from other * Registers a {@link BroadcastReceiver} that's not intended to receive broadcasts from other
* apps. This will be enforced by specifying {@link Context#RECEIVER_NOT_EXPORTED} if {@link * apps. This will be enforced by specifying {@link Context#RECEIVER_NOT_EXPORTED} if {@link
* #SDK_INT} is 33 or above. * Build.VERSION#SDK_INT} is 33 or above.
* *
* <p>Do not use this method if registering a receiver for a <a * <p>Do not use this method if registering a receiver for a <a
* href="https://android.googlesource.com/platform/frameworks/base/+/master/core/res/AndroidManifest.xml">protected * href="https://android.googlesource.com/platform/frameworks/base/+/master/core/res/AndroidManifest.xml">protected
@ -264,7 +263,7 @@ public final class Util {
@Nullable @Nullable
public static Intent registerReceiverNotExported( public static Intent registerReceiverNotExported(
Context context, @Nullable BroadcastReceiver receiver, IntentFilter filter) { Context context, @Nullable BroadcastReceiver receiver, IntentFilter filter) {
if (SDK_INT < 33) { if (Build.VERSION.SDK_INT < 33) {
return context.registerReceiver(receiver, filter); return context.registerReceiver(receiver, filter);
} else { } else {
return context.registerReceiver(receiver, filter, Context.RECEIVER_NOT_EXPORTED); return context.registerReceiver(receiver, filter, Context.RECEIVER_NOT_EXPORTED);
@ -272,8 +271,8 @@ public final class Util {
} }
/** /**
* Calls {@link Context#startForegroundService(Intent)} if {@link #SDK_INT} is 26 or higher, or * Calls {@link Context#startForegroundService(Intent)} if {@link Build.VERSION#SDK_INT} is 26 or
* {@link Context#startService(Intent)} otherwise. * higher, or {@link Context#startService(Intent)} otherwise.
* *
* @param context The context to call. * @param context The context to call.
* @param intent The intent to pass to the called method. * @param intent The intent to pass to the called method.
@ -282,7 +281,7 @@ public final class Util {
@UnstableApi @UnstableApi
@Nullable @Nullable
public static ComponentName startForegroundService(Context context, Intent intent) { public static ComponentName startForegroundService(Context context, Intent intent) {
if (SDK_INT >= 26) { if (Build.VERSION.SDK_INT >= 26) {
return context.startForegroundService(intent); return context.startForegroundService(intent);
} else { } else {
return context.startService(intent); return context.startService(intent);
@ -307,7 +306,7 @@ public final class Util {
Notification notification, Notification notification,
int foregroundServiceType, int foregroundServiceType,
String foregroundServiceManifestType) { String foregroundServiceManifestType) {
if (Util.SDK_INT >= 29) { if (Build.VERSION.SDK_INT >= 29) {
Api29.startForeground( Api29.startForeground(
service, service,
notificationId, notificationId,
@ -352,7 +351,7 @@ public final class Util {
*/ */
public static boolean maybeRequestReadStoragePermission( public static boolean maybeRequestReadStoragePermission(
Activity activity, MediaItem... mediaItems) { Activity activity, MediaItem... mediaItems) {
if (SDK_INT < 23) { if (Build.VERSION.SDK_INT < 23) {
return false; return false;
} }
for (MediaItem mediaItem : mediaItems) { for (MediaItem mediaItem : mediaItems) {
@ -377,7 +376,7 @@ public final class Util {
if (!isReadStoragePermissionRequestNeeded(activity, uri)) { if (!isReadStoragePermissionRequestNeeded(activity, uri)) {
return false; return false;
} }
if (SDK_INT < 33) { if (Build.VERSION.SDK_INT < 33) {
return requestExternalStoragePermission(activity); return requestExternalStoragePermission(activity);
} else { } else {
return requestReadMediaPermissions(activity); return requestReadMediaPermissions(activity);
@ -386,7 +385,7 @@ public final class Util {
@ChecksSdkIntAtLeast(api = 23) @ChecksSdkIntAtLeast(api = 23)
private static boolean isReadStoragePermissionRequestNeeded(Activity activity, Uri uri) { private static boolean isReadStoragePermissionRequestNeeded(Activity activity, Uri uri) {
if (SDK_INT < 23) { if (Build.VERSION.SDK_INT < 23) {
// Permission automatically granted via manifest below API 23. // Permission automatically granted via manifest below API 23.
return false; return false;
} }
@ -440,7 +439,7 @@ public final class Util {
* @return Whether it may be possible to load the URIs of the given media items. * @return Whether it may be possible to load the URIs of the given media items.
*/ */
public static boolean checkCleartextTrafficPermitted(MediaItem... mediaItems) { public static boolean checkCleartextTrafficPermitted(MediaItem... mediaItems) {
if (SDK_INT < 24) { if (Build.VERSION.SDK_INT < 24) {
// We assume cleartext traffic is permitted. // We assume cleartext traffic is permitted.
return true; return true;
} }
@ -511,7 +510,7 @@ public final class Util {
return false; return false;
} }
if (Util.SDK_INT >= 31) { if (Build.VERSION.SDK_INT >= 31) {
return sparseArray1.contentEquals(sparseArray2); return sparseArray1.contentEquals(sparseArray2);
} }
@ -540,7 +539,7 @@ public final class Util {
*/ */
@UnstableApi @UnstableApi
public static <T> int contentHashCode(SparseArray<T> sparseArray) { public static <T> int contentHashCode(SparseArray<T> sparseArray) {
if (Util.SDK_INT >= 31) { if (Build.VERSION.SDK_INT >= 31) {
return sparseArray.contentHashCode(); return sparseArray.contentHashCode();
} }
int hash = 17; int hash = 17;
@ -2296,7 +2295,7 @@ public final class Util {
case 8: case 8:
return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND; return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
case 10: case 10:
if (Util.SDK_INT >= 32) { if (Build.VERSION.SDK_INT >= 32) {
return AudioFormat.CHANNEL_OUT_5POINT1POINT4; return AudioFormat.CHANNEL_OUT_5POINT1POINT4;
} else { } else {
// Before API 32, height channel masks are not available. For those 10-channel streams // Before API 32, height channel masks are not available. For those 10-channel streams
@ -2306,7 +2305,7 @@ public final class Util {
case 12: case 12:
return AudioFormat.CHANNEL_OUT_7POINT1POINT4; return AudioFormat.CHANNEL_OUT_7POINT1POINT4;
case 24: case 24:
if (Util.SDK_INT >= 32) { if (Build.VERSION.SDK_INT >= 32) {
return AudioFormat.CHANNEL_OUT_7POINT1POINT4 return AudioFormat.CHANNEL_OUT_7POINT1POINT4
| AudioFormat.CHANNEL_OUT_FRONT_LEFT_OF_CENTER | AudioFormat.CHANNEL_OUT_FRONT_LEFT_OF_CENTER
| AudioFormat.CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | AudioFormat.CHANNEL_OUT_FRONT_RIGHT_OF_CENTER
@ -3070,7 +3069,9 @@ public final class Util {
/** Returns the default {@link Locale.Category#DISPLAY DISPLAY} {@link Locale}. */ /** Returns the default {@link Locale.Category#DISPLAY DISPLAY} {@link Locale}. */
@UnstableApi @UnstableApi
public static Locale getDefaultDisplayLocale() { public static Locale getDefaultDisplayLocale() {
return SDK_INT >= 24 ? Locale.getDefault(Locale.Category.DISPLAY) : Locale.getDefault(); return Build.VERSION.SDK_INT >= 24
? Locale.getDefault(Locale.Category.DISPLAY)
: Locale.getDefault();
} }
/** /**
@ -3165,7 +3166,7 @@ public final class Util {
*/ */
@UnstableApi @UnstableApi
public static boolean isAutomotive(Context context) { public static boolean isAutomotive(Context context) {
return SDK_INT >= 23 return Build.VERSION.SDK_INT >= 23
&& context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); && context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
} }
@ -3241,7 +3242,7 @@ public final class Util {
// vendor.display-size instead. // vendor.display-size instead.
@Nullable @Nullable
String displaySize = String displaySize =
SDK_INT < 28 Build.VERSION.SDK_INT < 28
? getSystemProperty("sys.display-size") ? getSystemProperty("sys.display-size")
: getSystemProperty("vendor.display-size"); : getSystemProperty("vendor.display-size");
// If we managed to read the display size, attempt to parse it. // If we managed to read the display size, attempt to parse it.
@ -3270,7 +3271,7 @@ public final class Util {
} }
Point displaySize = new Point(); Point displaySize = new Point();
if (SDK_INT >= 23) { if (Build.VERSION.SDK_INT >= 23) {
getDisplaySizeV23(display, displaySize); getDisplaySizeV23(display, displaySize);
} else { } else {
display.getRealSize(displaySize); display.getRealSize(displaySize);
@ -3324,9 +3325,9 @@ public final class Util {
return true; return true;
case MimeTypes.IMAGE_HEIF: case MimeTypes.IMAGE_HEIF:
case MimeTypes.IMAGE_HEIC: case MimeTypes.IMAGE_HEIC:
return Util.SDK_INT >= 26; return Build.VERSION.SDK_INT >= 26;
case MimeTypes.IMAGE_AVIF: case MimeTypes.IMAGE_AVIF:
return Util.SDK_INT >= 34; return Build.VERSION.SDK_INT >= 34;
default: default:
return false; return false;
} }
@ -3526,12 +3527,12 @@ public final class Util {
// full. // full.
// Some devices might drop frames despite setting {@link // Some devices might drop frames despite setting {@link
// MediaFormat#KEY_ALLOW_FRAME_DROP} to 0. See b/307518793, b/289983935 and b/353487886. // MediaFormat#KEY_ALLOW_FRAME_DROP} to 0. See b/307518793, b/289983935 and b/353487886.
return SDK_INT < 29 return Build.VERSION.SDK_INT < 29
|| context.getApplicationInfo().targetSdkVersion < 29 || context.getApplicationInfo().targetSdkVersion < 29
|| ((SDK_INT == 30 || ((Build.VERSION.SDK_INT == 30
&& (Ascii.equalsIgnoreCase(Build.MODEL, "moto g(20)") && (Ascii.equalsIgnoreCase(Build.MODEL, "moto g(20)")
|| Ascii.equalsIgnoreCase(Build.MODEL, "rmx3231"))) || Ascii.equalsIgnoreCase(Build.MODEL, "rmx3231")))
|| (SDK_INT == 34 && Ascii.equalsIgnoreCase(Build.MODEL, "sm-x200"))); || (Build.VERSION.SDK_INT == 34 && Ascii.equalsIgnoreCase(Build.MODEL, "sm-x200")));
} }
/** /**
@ -3818,7 +3819,7 @@ public final class Util {
private static String[] getSystemLocales() { private static String[] getSystemLocales() {
Configuration config = Resources.getSystem().getConfiguration(); Configuration config = Resources.getSystem().getConfiguration();
return SDK_INT >= 24 return Build.VERSION.SDK_INT >= 24
? getSystemLocalesV24(config) ? getSystemLocalesV24(config)
: new String[] {getLocaleLanguageTag(config.locale)}; : new String[] {getLocaleLanguageTag(config.locale)};
} }

View File

@ -17,6 +17,7 @@ package androidx.media3.common.util;
import static android.net.NetworkInfo.State.CONNECTED; import static android.net.NetworkInfo.State.CONNECTED;
import static android.net.NetworkInfo.State.DISCONNECTED; import static android.net.NetworkInfo.State.DISCONNECTED;
import static android.os.Build.VERSION.SDK_INT;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -238,7 +239,7 @@ public class NetworkTypeObserverTest {
ConnectivityManager connectivityManager = ConnectivityManager connectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Shadows.shadowOf(connectivityManager).setActiveNetworkInfo(networkInfo); Shadows.shadowOf(connectivityManager).setActiveNetworkInfo(networkInfo);
if (Util.SDK_INT >= 31) { if (SDK_INT >= 31) {
TelephonyManager telephonyManager = TelephonyManager telephonyManager =
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
Object displayInfo = Object displayInfo =

View File

@ -15,12 +15,13 @@
*/ */
package androidx.media3.decoder; package androidx.media3.decoder;
import static android.os.Build.VERSION.SDK_INT;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
/** /**
* Metadata describing the structure of an encrypted input sample. * Metadata describing the structure of an encrypted input sample.
@ -90,7 +91,7 @@ public final class CryptoInfo {
public CryptoInfo() { public CryptoInfo() {
frameworkCryptoInfo = new android.media.MediaCodec.CryptoInfo(); frameworkCryptoInfo = new android.media.MediaCodec.CryptoInfo();
patternHolder = Util.SDK_INT >= 24 ? new PatternHolderV24(frameworkCryptoInfo) : null; patternHolder = SDK_INT >= 24 ? new PatternHolderV24(frameworkCryptoInfo) : null;
} }
/** /**
@ -121,7 +122,7 @@ public final class CryptoInfo {
frameworkCryptoInfo.key = key; frameworkCryptoInfo.key = key;
frameworkCryptoInfo.iv = iv; frameworkCryptoInfo.iv = iv;
frameworkCryptoInfo.mode = mode; frameworkCryptoInfo.mode = mode;
if (Util.SDK_INT >= 24) { if (SDK_INT >= 24) {
Assertions.checkNotNull(patternHolder).set(encryptedBlocks, clearBlocks); Assertions.checkNotNull(patternHolder).set(encryptedBlocks, clearBlocks);
} }
} }

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.decoder.iamf; package androidx.media3.decoder.iamf;
import static android.os.Build.VERSION.SDK_INT;
import static com.google.common.truth.Truth.assertWithMessage; import static com.google.common.truth.Truth.assertWithMessage;
import android.content.Context; import android.content.Context;
@ -28,7 +29,6 @@ import androidx.media3.common.AudioAttributes;
import androidx.media3.common.MediaItem; import androidx.media3.common.MediaItem;
import androidx.media3.common.PlaybackException; import androidx.media3.common.PlaybackException;
import androidx.media3.common.Player; import androidx.media3.common.Player;
import androidx.media3.common.util.Util;
import androidx.media3.datasource.DefaultDataSource; import androidx.media3.datasource.DefaultDataSource;
import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.Renderer; import androidx.media3.exoplayer.Renderer;
@ -99,7 +99,7 @@ public class IamfPlaybackTest {
@Override @Override
public void run() { public void run() {
Looper.prepare(); Looper.prepare();
if (Util.SDK_INT >= 32) { // Spatializer is only available on API 32 and above. if (SDK_INT >= 32) { // Spatializer is only available on API 32 and above.
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
// Lint can't follow the indirection from AudioFormat.ENCODING_PCM_16BIT to // Lint can't follow the indirection from AudioFormat.ENCODING_PCM_16BIT to
// IamfDecoder.OUTPUT_PCM_ENCODING. // IamfDecoder.OUTPUT_PCM_ENCODING.

View File

@ -15,6 +15,8 @@
*/ */
package androidx.media3.decoder.iamf; package androidx.media3.decoder.iamf;
import static android.os.Build.VERSION.SDK_INT;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.media.AudioFormat; import android.media.AudioFormat;
@ -92,7 +94,7 @@ public class LibiamfAudioRenderer extends DecoderAudioRenderer<IamfDecoder> {
@SuppressLint("WrongConstant") @SuppressLint("WrongConstant")
private boolean isSpatializationSupported() { private boolean isSpatializationSupported() {
// Spatializer is only available on API 32 and above. // Spatializer is only available on API 32 and above.
if (Util.SDK_INT < 32) { if (SDK_INT < 32) {
return false; return false;
} }

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.effect; package androidx.media3.effect;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
@ -32,7 +33,6 @@ import androidx.media3.common.GlTextureInfo;
import androidx.media3.common.VideoFrameProcessingException; import androidx.media3.common.VideoFrameProcessingException;
import androidx.media3.common.util.GlUtil; import androidx.media3.common.util.GlUtil;
import androidx.media3.common.util.TimestampIterator; import androidx.media3.common.util.TimestampIterator;
import androidx.media3.common.util.Util;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@ -218,7 +218,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/* rboId= */ C.INDEX_UNSET, /* rboId= */ C.INDEX_UNSET,
frameInfo.format.width, frameInfo.format.width,
frameInfo.format.height); frameInfo.format.height);
if (Util.SDK_INT >= 34 && bitmap.hasGainmap()) { if (SDK_INT >= 34 && bitmap.hasGainmap()) {
checkNotNull(repeatingGainmapShaderProgram).setGainmap(checkNotNull(bitmap.getGainmap())); checkNotNull(repeatingGainmapShaderProgram).setGainmap(checkNotNull(bitmap.getGainmap()));
} }
if (signalRepeatingSequence) { if (signalRepeatingSequence) {

View File

@ -15,9 +15,9 @@
*/ */
package androidx.media3.effect; package androidx.media3.effect;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Util.SDK_INT;
import static com.google.common.util.concurrent.Futures.immediateFailedFuture; import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
import android.opengl.GLES20; import android.opengl.GLES20;

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.effect; package androidx.media3.effect;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.GlUtil.getDefaultEglDisplay; import static androidx.media3.common.util.GlUtil.getDefaultEglDisplay;
import static androidx.media3.effect.DefaultVideoFrameProcessor.WORKING_COLOR_SPACE_DEFAULT; import static androidx.media3.effect.DefaultVideoFrameProcessor.WORKING_COLOR_SPACE_DEFAULT;
@ -41,7 +42,6 @@ import androidx.media3.common.VideoFrameProcessingException;
import androidx.media3.common.util.GlUtil; import androidx.media3.common.util.GlUtil;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@ -221,7 +221,7 @@ public final class DebugViewShaderProgram implements GlShaderProgram {
// Therefore, convert HLG to PQ below API 34, so that HLG input can be displayed properly on // Therefore, convert HLG to PQ below API 34, so that HLG input can be displayed properly on
// API 33. // API 33.
this.outputColorTransfer = this.outputColorTransfer =
outputColorTransfer == C.COLOR_TRANSFER_HLG && Util.SDK_INT < 34 outputColorTransfer == C.COLOR_TRANSFER_HLG && SDK_INT < 34
? C.COLOR_TRANSFER_ST2084 ? C.COLOR_TRANSFER_ST2084
: outputColorTransfer; : outputColorTransfer;
surfaceView.getHolder().addCallback(this); surfaceView.getHolder().addCallback(this);

View File

@ -17,6 +17,7 @@ package androidx.media3.effect;
import static android.opengl.GLES20.GL_FALSE; import static android.opengl.GLES20.GL_FALSE;
import static android.opengl.GLES20.GL_TRUE; import static android.opengl.GLES20.GL_TRUE;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.VideoFrameProcessor.INPUT_TYPE_BITMAP; import static androidx.media3.common.VideoFrameProcessor.INPUT_TYPE_BITMAP;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
@ -36,7 +37,6 @@ import androidx.media3.common.util.GlProgram;
import androidx.media3.common.util.GlUtil; import androidx.media3.common.util.GlUtil;
import androidx.media3.common.util.GlUtil.GlException; import androidx.media3.common.util.GlUtil.GlException;
import androidx.media3.common.util.Size; import androidx.media3.common.util.Size;
import androidx.media3.common.util.Util;
import androidx.media3.effect.DefaultVideoFrameProcessor.WorkingColorSpace; import androidx.media3.effect.DefaultVideoFrameProcessor.WorkingColorSpace;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.io.IOException; import java.io.IOException;
@ -733,7 +733,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
if (lastGainmap == null) { if (lastGainmap == null) {
return; return;
} }
if (Util.SDK_INT < 34) { if (SDK_INT < 34) {
throw new IllegalStateException("Gainmaps not supported under API 34."); throw new IllegalStateException("Gainmaps not supported under API 34.");
} }
glProgram.setSamplerTexIdUniform("uGainmapTexSampler", gainmapTexId, /* texUnitIndex= */ 1); glProgram.setSamplerTexIdUniform("uGainmapTexSampler", gainmapTexId, /* texUnitIndex= */ 1);

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.effect; package androidx.media3.effect;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
@ -619,7 +620,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
} }
if (ColorInfo.isTransferHdr(outputColorInfo)) { if (ColorInfo.isTransferHdr(outputColorInfo)) {
checkArgument( checkArgument(
Util.SDK_INT >= 34 && inputBitmap.hasGainmap(), SDK_INT >= 34 && inputBitmap.hasGainmap(),
"VideoFrameProcessor configured for HDR output, but either received SDR input, or is on" "VideoFrameProcessor configured for HDR output, but either received SDR input, or is on"
+ " an API level that doesn't support gainmaps. SDR to HDR tonemapping is not" + " an API level that doesn't support gainmaps. SDR to HDR tonemapping is not"
+ " supported."); + " supported.");

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.effect; package androidx.media3.effect;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
@ -36,7 +37,6 @@ import androidx.media3.common.VideoFrameProcessingException;
import androidx.media3.common.util.GlProgram; import androidx.media3.common.util.GlProgram;
import androidx.media3.common.util.GlUtil; import androidx.media3.common.util.GlUtil;
import androidx.media3.common.util.Size; import androidx.media3.common.util.Size;
import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.io.IOException; import java.io.IOException;
@ -212,7 +212,7 @@ import java.io.IOException;
hdrTypes[i] = HDR_TYPE_TEXT; hdrTypes[i] = HDR_TYPE_TEXT;
overlaySamplersAvailable -= 1; overlaySamplersAvailable -= 1;
} else if (overlay instanceof BitmapOverlay) { } else if (overlay instanceof BitmapOverlay) {
checkState(Util.SDK_INT >= 34); checkState(SDK_INT >= 34);
hdrTypes[i] = HDR_TYPE_ULTRA_HDR; hdrTypes[i] = HDR_TYPE_ULTRA_HDR;
// Each UltraHDR overlay uses an extra texture to apply the gainmap to the base in the // Each UltraHDR overlay uses an extra texture to apply the gainmap to the base in the
// shader. // shader.

View File

@ -15,8 +15,8 @@
*/ */
package androidx.media3.effect; package androidx.media3.effect;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Util.SDK_INT;
import static java.lang.Math.ceil; import static java.lang.Math.ceil;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer; package androidx.media3.exoplayer;
import static android.os.Build.VERSION.SDK_INT;
import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.ElementType.TYPE_USE;
import android.content.Context; import android.content.Context;
@ -29,7 +30,6 @@ import androidx.media3.common.C;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.audio.AudioRendererEventListener; import androidx.media3.exoplayer.audio.AudioRendererEventListener;
import androidx.media3.exoplayer.audio.AudioSink; import androidx.media3.exoplayer.audio.AudioSink;
import androidx.media3.exoplayer.audio.DefaultAudioSink; import androidx.media3.exoplayer.audio.DefaultAudioSink;
@ -440,7 +440,7 @@ public class DefaultRenderersFactory implements RenderersFactory {
.setMaxDroppedFramesToNotify(MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY) .setMaxDroppedFramesToNotify(MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY)
.experimentalSetParseAv1SampleDependencies(parseAv1SampleDependencies) .experimentalSetParseAv1SampleDependencies(parseAv1SampleDependencies)
.experimentalSetLateThresholdToDropDecoderInputUs(lateThresholdToDropDecoderInputUs); .experimentalSetLateThresholdToDropDecoderInputUs(lateThresholdToDropDecoderInputUs);
if (Util.SDK_INT >= 34) { if (SDK_INT >= 34) {
videoRendererBuilder = videoRendererBuilder =
videoRendererBuilder.experimentalSetEnableMediaCodecBufferDecodeOnlyFlag( videoRendererBuilder.experimentalSetEnableMediaCodecBufferDecodeOnlyFlag(
enableMediaCodecBufferDecodeOnlyFlag); enableMediaCodecBufferDecodeOnlyFlag);
@ -889,7 +889,7 @@ public class DefaultRenderersFactory implements RenderersFactory {
.setMaxDroppedFramesToNotify(MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY) .setMaxDroppedFramesToNotify(MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY)
.experimentalSetParseAv1SampleDependencies(parseAv1SampleDependencies) .experimentalSetParseAv1SampleDependencies(parseAv1SampleDependencies)
.experimentalSetLateThresholdToDropDecoderInputUs(lateThresholdToDropDecoderInputUs); .experimentalSetLateThresholdToDropDecoderInputUs(lateThresholdToDropDecoderInputUs);
if (Util.SDK_INT >= 34) { if (SDK_INT >= 34) {
builder = builder =
builder.experimentalSetEnableMediaCodecBufferDecodeOnlyFlag( builder.experimentalSetEnableMediaCodecBufferDecodeOnlyFlag(
enableMediaCodecBufferDecodeOnlyFlag); enableMediaCodecBufferDecodeOnlyFlag);

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer; package androidx.media3.exoplayer;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkStateNotNull; import static androidx.media3.common.util.Assertions.checkStateNotNull;
@ -48,9 +49,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** Creates the default {@link SuitableOutputChecker}. */ /** Creates the default {@link SuitableOutputChecker}. */
public DefaultSuitableOutputChecker() { public DefaultSuitableOutputChecker() {
if (Util.SDK_INT >= 35) { if (SDK_INT >= 35) {
impl = new ImplApi35(); impl = new ImplApi35();
} else if (Util.SDK_INT >= 23) { } else if (SDK_INT >= 23) {
impl = new ImplApi23(); impl = new ImplApi23();
} else { } else {
impl = null; impl = null;
@ -255,18 +256,18 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|| device.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET) { || device.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET) {
return true; return true;
} }
if (Util.SDK_INT >= 26 && device.getType() == AudioDeviceInfo.TYPE_USB_HEADSET) { if (SDK_INT >= 26 && device.getType() == AudioDeviceInfo.TYPE_USB_HEADSET) {
return true; return true;
} }
if (Util.SDK_INT >= 28 && device.getType() == AudioDeviceInfo.TYPE_HEARING_AID) { if (SDK_INT >= 28 && device.getType() == AudioDeviceInfo.TYPE_HEARING_AID) {
return true; return true;
} }
if (Util.SDK_INT >= 31 if (SDK_INT >= 31
&& (device.getType() == AudioDeviceInfo.TYPE_BLE_HEADSET && (device.getType() == AudioDeviceInfo.TYPE_BLE_HEADSET
|| device.getType() == AudioDeviceInfo.TYPE_BLE_SPEAKER)) { || device.getType() == AudioDeviceInfo.TYPE_BLE_SPEAKER)) {
return true; return true;
} }
if (Util.SDK_INT >= 33 && device.getType() == AudioDeviceInfo.TYPE_BLE_BROADCAST) { if (SDK_INT >= 33 && device.getType() == AudioDeviceInfo.TYPE_BLE_BROADCAST) {
return true; return true;
} }
} }

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer; package androidx.media3.exoplayer;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.C.AUDIO_SESSION_ID_UNSET; import static androidx.media3.common.C.AUDIO_SESSION_ID_UNSET;
import static androidx.media3.common.C.TRACK_TYPE_AUDIO; import static androidx.media3.common.C.TRACK_TYPE_AUDIO;
import static androidx.media3.common.C.TRACK_TYPE_CAMERA_MOTION; import static androidx.media3.common.C.TRACK_TYPE_CAMERA_MOTION;
@ -394,7 +395,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
if (builder.foregroundModeTimeoutMs > 0) { if (builder.foregroundModeTimeoutMs > 0) {
internalPlayer.experimentalSetForegroundModeTimeoutMs(builder.foregroundModeTimeoutMs); internalPlayer.experimentalSetForegroundModeTimeoutMs(builder.foregroundModeTimeoutMs);
} }
if (Util.SDK_INT >= 31) { if (SDK_INT >= 31) {
Api31.registerMediaMetricsListener( Api31.registerMediaMetricsListener(
applicationContext, /* player= */ this, builder.usePlatformDiagnostics, playerId); applicationContext, /* player= */ this, builder.usePlatformDiagnostics, playerId);
} }

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer; package androidx.media3.exoplayer;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.annotation.VisibleForTesting.NONE; import static androidx.annotation.VisibleForTesting.NONE;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
@ -45,7 +46,6 @@ import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
import androidx.media3.common.util.MediaFormatUtil; import androidx.media3.common.util.MediaFormatUtil;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.datasource.DataSource; import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DataSourceUtil; import androidx.media3.datasource.DataSourceUtil;
import androidx.media3.datasource.DataSpec; import androidx.media3.datasource.DataSpec;
@ -1003,7 +1003,7 @@ public final class MediaExtractorCompat {
Format format = getFormat(scratchFormatHolder, scratchNoDataDecoderInputBuffer); Format format = getFormat(scratchFormatHolder, scratchNoDataDecoderInputBuffer);
MediaFormat mediaFormatResult = MediaFormatUtil.createMediaFormatFromFormat(format); MediaFormat mediaFormatResult = MediaFormatUtil.createMediaFormatFromFormat(format);
if (compatibilityTrackMimeType != null) { if (compatibilityTrackMimeType != null) {
if (Util.SDK_INT >= 29) { if (SDK_INT >= 29) {
mediaFormatResult.removeKey(MediaFormat.KEY_CODECS_STRING); mediaFormatResult.removeKey(MediaFormat.KEY_CODECS_STRING);
} }
mediaFormatResult.setString(MediaFormat.KEY_MIME, compatibilityTrackMimeType); mediaFormatResult.setString(MediaFormat.KEY_MIME, compatibilityTrackMimeType);

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer; package androidx.media3.exoplayer;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
@ -31,7 +32,6 @@ import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.BackgroundThreadStateHandler; import androidx.media3.common.util.BackgroundThreadStateHandler;
import androidx.media3.common.util.Clock; import androidx.media3.common.util.Clock;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
import androidx.media3.common.util.Util;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** A manager that wraps {@link AudioManager} to control/listen audio stream volume. */ /** A manager that wraps {@link AudioManager} to control/listen audio stream volume. */
@ -247,7 +247,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
return state; return state;
} }
checkNotNull(audioManager); checkNotNull(audioManager);
if (Util.SDK_INT >= 23) { if (SDK_INT >= 23) {
audioManager.adjustStreamVolume( audioManager.adjustStreamVolume(
state.streamType, state.streamType,
muted ? AudioManager.ADJUST_MUTE : AudioManager.ADJUST_UNMUTE, muted ? AudioManager.ADJUST_MUTE : AudioManager.ADJUST_UNMUTE,

View File

@ -764,7 +764,7 @@ public final class MediaMetricsListener
int subErrorCode = Util.getErrorCodeFromPlatformDiagnosticsInfo(diagnosticsInfo); int subErrorCode = Util.getErrorCodeFromPlatformDiagnosticsInfo(diagnosticsInfo);
int errorCode = getDrmErrorCode(subErrorCode); int errorCode = getDrmErrorCode(subErrorCode);
return new ErrorInfo(errorCode, subErrorCode); return new ErrorInfo(errorCode, subErrorCode);
} else if (Util.SDK_INT >= 23 && cause instanceof MediaDrmResetException) { } else if (cause instanceof MediaDrmResetException) {
return new ErrorInfo(PlaybackErrorEvent.ERROR_DRM_SYSTEM_ERROR, /* subErrorCode= */ 0); return new ErrorInfo(PlaybackErrorEvent.ERROR_DRM_SYSTEM_ERROR, /* subErrorCode= */ 0);
} else if (cause instanceof NotProvisionedException) { } else if (cause instanceof NotProvisionedException) {
return new ErrorInfo( return new ErrorInfo(

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.analytics; package androidx.media3.exoplayer.analytics;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
@ -22,7 +23,6 @@ import android.media.metrics.LogSessionId;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.ExoPlayer.Builder; import androidx.media3.exoplayer.ExoPlayer.Builder;
import java.util.Objects; import java.util.Objects;
@ -55,7 +55,7 @@ public final class PlayerId {
*/ */
public PlayerId(String playerName) { public PlayerId(String playerName) {
this.name = playerName; this.name = playerName;
this.logSessionIdApi31 = Util.SDK_INT >= 31 ? new LogSessionIdApi31() : null; this.logSessionIdApi31 = SDK_INT >= 31 ? new LogSessionIdApi31() : null;
equalityToken = new Object(); equalityToken = new Object();
} }

View File

@ -16,6 +16,7 @@
package androidx.media3.exoplayer.audio; package androidx.media3.exoplayer.audio;
import static android.media.AudioFormat.CHANNEL_OUT_STEREO; import static android.media.AudioFormat.CHANNEL_OUT_STEREO;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static java.lang.Math.max; import static java.lang.Math.max;
@ -121,7 +122,7 @@ public final class AudioCapabilities {
Context context, AudioAttributes audioAttributes, @Nullable AudioDeviceInfo routedDevice) { Context context, AudioAttributes audioAttributes, @Nullable AudioDeviceInfo routedDevice) {
@Nullable @Nullable
AudioDeviceInfoApi23 routedDeviceApi23 = AudioDeviceInfoApi23 routedDeviceApi23 =
Util.SDK_INT >= 23 && routedDevice != null ? new AudioDeviceInfoApi23(routedDevice) : null; SDK_INT >= 23 && routedDevice != null ? new AudioDeviceInfoApi23(routedDevice) : null;
return getCapabilitiesInternal(context, audioAttributes, routedDeviceApi23); return getCapabilitiesInternal(context, audioAttributes, routedDeviceApi23);
} }
@ -147,11 +148,11 @@ public final class AudioCapabilities {
AudioDeviceInfoApi23 currentDevice = AudioDeviceInfoApi23 currentDevice =
routedDevice != null routedDevice != null
? routedDevice ? routedDevice
: Util.SDK_INT >= 33 : SDK_INT >= 33
? Api33.getDefaultRoutedDeviceForAttributes(audioManager, audioAttributes) ? Api33.getDefaultRoutedDeviceForAttributes(audioManager, audioAttributes)
: null; : null;
if (Util.SDK_INT >= 33 && (Util.isTv(context) || Util.isAutomotive(context))) { if (SDK_INT >= 33 && (Util.isTv(context) || Util.isAutomotive(context))) {
// TV or automotive devices generally shouldn't support audio offload for surround encodings, // TV or automotive devices generally shouldn't support audio offload for surround encodings,
// so the encodings we get from AudioManager.getDirectProfilesForAttributes should include // so the encodings we get from AudioManager.getDirectProfilesForAttributes should include
// the PCM encodings and surround encodings for passthrough mode. // the PCM encodings and surround encodings for passthrough mode.
@ -160,7 +161,7 @@ public final class AudioCapabilities {
// If a connection to Bluetooth device is detected, we only return the minimum capabilities that // If a connection to Bluetooth device is detected, we only return the minimum capabilities that
// is supported by all the devices. // is supported by all the devices.
if (Util.SDK_INT >= 23 && Api23.isBluetoothConnected(audioManager, currentDevice)) { if (SDK_INT >= 23 && Api23.isBluetoothConnected(audioManager, currentDevice)) {
return DEFAULT_AUDIO_CAPABILITIES; return DEFAULT_AUDIO_CAPABILITIES;
} }
@ -171,7 +172,7 @@ public final class AudioCapabilities {
// offload, as well as for encodings we want to list for passthrough mode. Therefore we only use // offload, as well as for encodings we want to list for passthrough mode. Therefore we only use
// it on TV and automotive devices, which generally shouldn't support audio offload for surround // it on TV and automotive devices, which generally shouldn't support audio offload for surround
// encodings. // encodings.
if (Util.SDK_INT >= 29 && (Util.isTv(context) || Util.isAutomotive(context))) { if (SDK_INT >= 29 && (Util.isTv(context) || Util.isAutomotive(context))) {
supportedEncodings.addAll(Api29.getDirectPlaybackSupportedEncodings(audioAttributes)); supportedEncodings.addAll(Api29.getDirectPlaybackSupportedEncodings(audioAttributes));
return new AudioCapabilities( return new AudioCapabilities(
getAudioProfiles(Ints.toArray(supportedEncodings.build()), DEFAULT_MAX_CHANNEL_COUNT)); getAudioProfiles(Ints.toArray(supportedEncodings.build()), DEFAULT_MAX_CHANNEL_COUNT));
@ -325,7 +326,7 @@ public final class AudioCapabilities {
audioProfile.getMaxSupportedChannelCountForPassthrough(sampleRate, audioAttributes); audioProfile.getMaxSupportedChannelCountForPassthrough(sampleRate, audioAttributes);
} else { } else {
channelCount = format.channelCount; channelCount = format.channelCount;
if (format.sampleMimeType.equals(MimeTypes.AUDIO_DTS_X) && Util.SDK_INT < 33) { if (format.sampleMimeType.equals(MimeTypes.AUDIO_DTS_X) && SDK_INT < 33) {
// Some DTS:X TVs reports ACTION_HDMI_AUDIO_PLUG.EXTRA_MAX_CHANNEL_COUNT as 8 // Some DTS:X TVs reports ACTION_HDMI_AUDIO_PLUG.EXTRA_MAX_CHANNEL_COUNT as 8
// instead of 10. See https://github.com/androidx/media/issues/396 // instead of 10. See https://github.com/androidx/media/issues/396
if (channelCount > 10) { if (channelCount > 10) {
@ -374,7 +375,7 @@ public final class AudioCapabilities {
} }
private static int getChannelConfigForPassthrough(int channelCount) { private static int getChannelConfigForPassthrough(int channelCount) {
if (Util.SDK_INT <= 28) { if (SDK_INT <= 28) {
// In passthrough mode the channel count used to configure the audio track doesn't affect how // In passthrough mode the channel count used to configure the audio track doesn't affect how
// the stream is handled, except that some devices do overly-strict channel configuration // the stream is handled, except that some devices do overly-strict channel configuration
// checks. Therefore we override the channel count so that a known-working channel // checks. Therefore we override the channel count so that a known-working channel
@ -388,7 +389,7 @@ public final class AudioCapabilities {
// Workaround for Nexus Player not reporting support for mono passthrough. See // Workaround for Nexus Player not reporting support for mono passthrough. See
// [Internal: b/34268671]. // [Internal: b/34268671].
if (Util.SDK_INT <= 26 && "fugu".equals(Build.DEVICE) && channelCount == 1) { if (SDK_INT <= 26 && "fugu".equals(Build.DEVICE) && channelCount == 1) {
channelCount = 2; channelCount = 2;
} }
@ -448,7 +449,7 @@ public final class AudioCapabilities {
private static final class AudioProfile { private static final class AudioProfile {
public static final AudioProfile DEFAULT_AUDIO_PROFILE = public static final AudioProfile DEFAULT_AUDIO_PROFILE =
(Util.SDK_INT >= 33) (SDK_INT >= 33)
? new AudioProfile( ? new AudioProfile(
C.ENCODING_PCM_16BIT, C.ENCODING_PCM_16BIT,
getAllChannelMasksForMaxChannelCount(DEFAULT_MAX_CHANNEL_COUNT)) getAllChannelMasksForMaxChannelCount(DEFAULT_MAX_CHANNEL_COUNT))
@ -492,7 +493,7 @@ public final class AudioCapabilities {
if (channelMasks != null) { if (channelMasks != null) {
// We built the AudioProfile on API 33. // We built the AudioProfile on API 33.
return maxChannelCount; return maxChannelCount;
} else if (Util.SDK_INT >= 29) { } else if (SDK_INT >= 29) {
return Api29.getMaxSupportedChannelCountForPassthrough( return Api29.getMaxSupportedChannelCountForPassthrough(
encoding, sampleRate, audioAttributes); encoding, sampleRate, audioAttributes);
} }
@ -574,11 +575,11 @@ public final class AudioCapabilities {
ImmutableSet.Builder<Integer> allBluetoothDeviceTypes = ImmutableSet.Builder<Integer> allBluetoothDeviceTypes =
new ImmutableSet.Builder<Integer>() new ImmutableSet.Builder<Integer>()
.add(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, AudioDeviceInfo.TYPE_BLUETOOTH_SCO); .add(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, AudioDeviceInfo.TYPE_BLUETOOTH_SCO);
if (Util.SDK_INT >= 31) { if (SDK_INT >= 31) {
allBluetoothDeviceTypes.add( allBluetoothDeviceTypes.add(
AudioDeviceInfo.TYPE_BLE_HEADSET, AudioDeviceInfo.TYPE_BLE_SPEAKER); AudioDeviceInfo.TYPE_BLE_HEADSET, AudioDeviceInfo.TYPE_BLE_SPEAKER);
} }
if (Util.SDK_INT >= 33) { if (SDK_INT >= 33) {
allBluetoothDeviceTypes.add(AudioDeviceInfo.TYPE_BLE_BROADCAST); allBluetoothDeviceTypes.add(AudioDeviceInfo.TYPE_BLE_BROADCAST);
} }
return allBluetoothDeviceTypes.build(); return allBluetoothDeviceTypes.build();
@ -594,7 +595,7 @@ public final class AudioCapabilities {
AudioAttributes audioAttributes) { AudioAttributes audioAttributes) {
ImmutableList.Builder<Integer> supportedEncodingsListBuilder = ImmutableList.builder(); ImmutableList.Builder<Integer> supportedEncodingsListBuilder = ImmutableList.builder();
for (int encoding : ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.keySet()) { for (int encoding : ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.keySet()) {
if (Util.SDK_INT < Util.getApiLevelThatAudioFormatIntroducedAudioEncoding(encoding)) { if (SDK_INT < Util.getApiLevelThatAudioFormatIntroducedAudioEncoding(encoding)) {
// Example: AudioFormat.ENCODING_DTS_UHD_P2 is supported only from API 34. // Example: AudioFormat.ENCODING_DTS_UHD_P2 is supported only from API 34.
continue; continue;
} }

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.audio; package androidx.media3.exoplayer.audio;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
@ -91,7 +92,7 @@ public final class AudioCapabilitiesReceiver {
context, context,
listener, listener,
audioAttributes, audioAttributes,
Util.SDK_INT >= 23 && routedDevice != null ? new AudioDeviceInfoApi23(routedDevice) : null); SDK_INT >= 23 && routedDevice != null ? new AudioDeviceInfoApi23(routedDevice) : null);
} }
/* package */ AudioCapabilitiesReceiver( /* package */ AudioCapabilitiesReceiver(
@ -105,7 +106,7 @@ public final class AudioCapabilitiesReceiver {
this.audioAttributes = audioAttributes; this.audioAttributes = audioAttributes;
this.routedDevice = routedDevice; this.routedDevice = routedDevice;
handler = Util.createHandlerForCurrentOrMainLooper(); handler = Util.createHandlerForCurrentOrMainLooper();
audioDeviceCallback = Util.SDK_INT >= 23 ? new AudioDeviceCallbackV23() : null; audioDeviceCallback = SDK_INT >= 23 ? new AudioDeviceCallbackV23() : null;
hdmiAudioPlugBroadcastReceiver = new HdmiAudioPlugBroadcastReceiver(); hdmiAudioPlugBroadcastReceiver = new HdmiAudioPlugBroadcastReceiver();
Uri externalSurroundSoundUri = AudioCapabilities.getExternalSurroundSoundGlobalSettingUri(); Uri externalSurroundSoundUri = AudioCapabilities.getExternalSurroundSoundGlobalSettingUri();
externalSurroundSoundSettingObserver = externalSurroundSoundSettingObserver =
@ -159,7 +160,7 @@ public final class AudioCapabilitiesReceiver {
if (externalSurroundSoundSettingObserver != null) { if (externalSurroundSoundSettingObserver != null) {
externalSurroundSoundSettingObserver.register(); externalSurroundSoundSettingObserver.register();
} }
if (Util.SDK_INT >= 23 && audioDeviceCallback != null) { if (SDK_INT >= 23 && audioDeviceCallback != null) {
Api23.registerAudioDeviceCallback(context, audioDeviceCallback, handler); Api23.registerAudioDeviceCallback(context, audioDeviceCallback, handler);
} }
Intent stickyIntent = Intent stickyIntent =
@ -183,7 +184,7 @@ public final class AudioCapabilitiesReceiver {
return; return;
} }
audioCapabilities = null; audioCapabilities = null;
if (Util.SDK_INT >= 23 && audioDeviceCallback != null) { if (SDK_INT >= 23 && audioDeviceCallback != null) {
Api23.unregisterAudioDeviceCallback(context, audioDeviceCallback); Api23.unregisterAudioDeviceCallback(context, audioDeviceCallback);
} }
context.unregisterReceiver(hdmiAudioPlugBroadcastReceiver); context.unregisterReceiver(hdmiAudioPlugBroadcastReceiver);

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.audio; package androidx.media3.exoplayer.audio;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Util.castNonNull; import static androidx.media3.common.util.Util.castNonNull;
import static androidx.media3.common.util.Util.durationUsToSampleCount; import static androidx.media3.common.util.Util.durationUsToSampleCount;
@ -618,8 +619,7 @@ import java.lang.reflect.Method;
* b/18899620, b/19187573, b/21145353]. * b/18899620, b/19187573, b/21145353].
*/ */
private static boolean needsPassthroughWorkarounds(@C.Encoding int outputEncoding) { private static boolean needsPassthroughWorkarounds(@C.Encoding int outputEncoding) {
return Util.SDK_INT < 23 return SDK_INT < 23 && (outputEncoding == C.ENCODING_AC3 || outputEncoding == C.ENCODING_E_AC3);
&& (outputEncoding == C.ENCODING_AC3 || outputEncoding == C.ENCODING_E_AC3);
} }
private long getPlaybackHeadPositionUs() { private long getPlaybackHeadPositionUs() {
@ -679,7 +679,7 @@ import java.lang.reflect.Method;
rawPlaybackHeadPosition += passthroughWorkaroundPauseOffset; rawPlaybackHeadPosition += passthroughWorkaroundPauseOffset;
} }
if (Util.SDK_INT <= 29) { if (SDK_INT <= 29) {
if (rawPlaybackHeadPosition == 0 if (rawPlaybackHeadPosition == 0
&& this.rawPlaybackHeadPosition > 0 && this.rawPlaybackHeadPosition > 0
&& state == PLAYSTATE_PLAYING) { && state == PLAYSTATE_PLAYING) {

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.audio; package androidx.media3.exoplayer.audio;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_DRM_SESSION_CHANGED; import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_DRM_SESSION_CHANGED;
import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_REUSE_NOT_IMPLEMENTED; import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_REUSE_NOT_IMPLEMENTED;
@ -762,7 +763,7 @@ public abstract class DecoderAudioRenderer<
audioSink.setAudioSessionId((Integer) message); audioSink.setAudioSessionId((Integer) message);
break; break;
case MSG_SET_PREFERRED_AUDIO_DEVICE: case MSG_SET_PREFERRED_AUDIO_DEVICE:
if (Util.SDK_INT >= 23) { if (SDK_INT >= 23) {
Api23.setAudioSinkPreferredDevice(audioSink, message); Api23.setAudioSinkPreferredDevice(audioSink, message);
} }
break; break;

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.audio; package androidx.media3.exoplayer.audio;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import android.content.Context; import android.content.Context;
@ -71,7 +72,7 @@ public final class DefaultAudioOffloadSupportProvider
checkNotNull(format); checkNotNull(format);
checkNotNull(audioAttributes); checkNotNull(audioAttributes);
if (Util.SDK_INT < 29 || format.sampleRate == Format.NO_VALUE) { if (SDK_INT < 29 || format.sampleRate == Format.NO_VALUE) {
return AudioOffloadSupport.DEFAULT_UNSUPPORTED; return AudioOffloadSupport.DEFAULT_UNSUPPORTED;
} }
@ -82,7 +83,7 @@ public final class DefaultAudioOffloadSupportProvider
@C.Encoding @C.Encoding
int encoding = MimeTypes.getEncoding(checkNotNull(format.sampleMimeType), format.codecs); int encoding = MimeTypes.getEncoding(checkNotNull(format.sampleMimeType), format.codecs);
if (encoding == C.ENCODING_INVALID if (encoding == C.ENCODING_INVALID
|| Util.SDK_INT < Util.getApiLevelThatAudioFormatIntroducedAudioEncoding(encoding)) { || SDK_INT < Util.getApiLevelThatAudioFormatIntroducedAudioEncoding(encoding)) {
// Example: AudioFormat.ENCODING_OPUS is supported only from API 30. // Example: AudioFormat.ENCODING_OPUS is supported only from API 30.
return AudioOffloadSupport.DEFAULT_UNSUPPORTED; return AudioOffloadSupport.DEFAULT_UNSUPPORTED;
} }
@ -99,7 +100,7 @@ public final class DefaultAudioOffloadSupportProvider
return AudioOffloadSupport.DEFAULT_UNSUPPORTED; return AudioOffloadSupport.DEFAULT_UNSUPPORTED;
} }
if (Util.SDK_INT >= 31) { if (SDK_INT >= 31) {
return Api31.getOffloadedPlaybackSupport( return Api31.getOffloadedPlaybackSupport(
audioFormat, audioFormat,
audioAttributes.getAudioAttributesV21().audioAttributes, audioAttributes.getAudioAttributesV21().audioAttributes,
@ -165,8 +166,7 @@ public final class DefaultAudioOffloadSupportProvider
// (b/191950723) Gapless is not supported pre-API 33 due to playback position // (b/191950723) Gapless is not supported pre-API 33 due to playback position
// issue upon transition of gapless tracks // issue upon transition of gapless tracks
boolean isGaplessSupported = boolean isGaplessSupported =
Util.SDK_INT > 32 SDK_INT > 32 && playbackOffloadSupport == AudioManager.PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED;
&& playbackOffloadSupport == AudioManager.PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED;
return audioOffloadSupport return audioOffloadSupport
.setIsFormatSupported(true) .setIsFormatSupported(true)
.setIsGaplessSupported(isGaplessSupported) .setIsGaplessSupported(isGaplessSupported)

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.audio; package androidx.media3.exoplayer.audio;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Util.constrainValue; import static androidx.media3.common.util.Util.constrainValue;
@ -598,7 +599,7 @@ public final class DefaultAudioSink implements AudioSink {
audioCapabilities = context != null ? null : builder.audioCapabilities; audioCapabilities = context != null ? null : builder.audioCapabilities;
audioProcessorChain = builder.audioProcessorChain; audioProcessorChain = builder.audioProcessorChain;
enableFloatOutput = builder.enableFloatOutput; enableFloatOutput = builder.enableFloatOutput;
preferAudioTrackPlaybackParams = Util.SDK_INT >= 23 && builder.enableAudioTrackPlaybackParams; preferAudioTrackPlaybackParams = SDK_INT >= 23 && builder.enableAudioTrackPlaybackParams;
offloadMode = OFFLOAD_MODE_DISABLED; offloadMode = OFFLOAD_MODE_DISABLED;
audioTrackBufferSizeProvider = builder.audioTrackBufferSizeProvider; audioTrackBufferSizeProvider = builder.audioTrackBufferSizeProvider;
audioOffloadSupportProvider = checkNotNull(builder.audioOffloadSupportProvider); audioOffloadSupportProvider = checkNotNull(builder.audioOffloadSupportProvider);
@ -851,7 +852,7 @@ public final class DefaultAudioSink implements AudioSink {
configuration.inputFormat.encoderDelay, configuration.inputFormat.encoderPadding); configuration.inputFormat.encoderDelay, configuration.inputFormat.encoderPadding);
} }
} }
if (Util.SDK_INT >= 31 && playerId != null) { if (SDK_INT >= 31 && playerId != null) {
Api31.setLogSessionIdOnAudioTrack(audioTrack, playerId); Api31.setLogSessionIdOnAudioTrack(audioTrack, playerId);
} }
audioSessionId = audioTrack.getAudioSessionId(); audioSessionId = audioTrack.getAudioSessionId();
@ -867,13 +868,13 @@ public final class DefaultAudioSink implements AudioSink {
audioTrack.attachAuxEffect(auxEffectInfo.effectId); audioTrack.attachAuxEffect(auxEffectInfo.effectId);
audioTrack.setAuxEffectSendLevel(auxEffectInfo.sendLevel); audioTrack.setAuxEffectSendLevel(auxEffectInfo.sendLevel);
} }
if (preferredDevice != null && Util.SDK_INT >= 23) { if (preferredDevice != null && SDK_INT >= 23) {
Api23.setPreferredDeviceOnAudioTrack(audioTrack, preferredDevice); Api23.setPreferredDeviceOnAudioTrack(audioTrack, preferredDevice);
if (audioCapabilitiesReceiver != null) { if (audioCapabilitiesReceiver != null) {
audioCapabilitiesReceiver.setRoutedDevice(preferredDevice.audioDeviceInfo); audioCapabilitiesReceiver.setRoutedDevice(preferredDevice.audioDeviceInfo);
} }
} }
if (Util.SDK_INT >= 24 && audioCapabilitiesReceiver != null) { if (SDK_INT >= 24 && audioCapabilitiesReceiver != null) {
onRoutingChangedListener = onRoutingChangedListener =
new OnRoutingChangedListenerApi24(audioTrack, audioCapabilitiesReceiver); new OnRoutingChangedListenerApi24(audioTrack, audioCapabilitiesReceiver);
} }
@ -1358,7 +1359,7 @@ public final class DefaultAudioSink implements AudioSink {
} }
private static boolean isAudioTrackDeadObject(int status) { private static boolean isAudioTrackDeadObject(int status) {
return (Util.SDK_INT >= 24 && status == AudioTrack.ERROR_DEAD_OBJECT) return (SDK_INT >= 24 && status == AudioTrack.ERROR_DEAD_OBJECT)
|| status == ERROR_NATIVE_DEAD_OBJECT; || status == ERROR_NATIVE_DEAD_OBJECT;
} }
@ -1370,9 +1371,7 @@ public final class DefaultAudioSink implements AudioSink {
@Override @Override
public boolean hasPendingData() { public boolean hasPendingData() {
return isAudioTrackInitialized() return isAudioTrackInitialized()
&& (Util.SDK_INT < 29 && (SDK_INT < 29 || !audioTrack.isOffloadedPlayback() || !handledOffloadOnPresentationEnded)
|| !audioTrack.isOffloadedPlayback()
|| !handledOffloadOnPresentationEnded)
&& audioTrackPositionTracker.hasPendingData(getWrittenFrames()); && audioTrackPositionTracker.hasPendingData(getWrittenFrames());
} }
@ -1474,7 +1473,7 @@ public final class DefaultAudioSink implements AudioSink {
if (!isAudioTrackInitialized()) { if (!isAudioTrackInitialized()) {
return C.TIME_UNSET; return C.TIME_UNSET;
} }
if (Util.SDK_INT >= 23) { if (SDK_INT >= 23) {
return Api23.getAudioTrackBufferSizeUs(audioTrack, configuration); return Api23.getAudioTrackBufferSizeUs(audioTrack, configuration);
} }
long byteRate = long byteRate =
@ -1505,7 +1504,7 @@ public final class DefaultAudioSink implements AudioSink {
@RequiresApi(29) @RequiresApi(29)
@Override @Override
public void setOffloadMode(@OffloadMode int offloadMode) { public void setOffloadMode(@OffloadMode int offloadMode) {
Assertions.checkState(Util.SDK_INT >= 29); Assertions.checkState(SDK_INT >= 29);
this.offloadMode = offloadMode; this.offloadMode = offloadMode;
} }
@ -1560,7 +1559,7 @@ public final class DefaultAudioSink implements AudioSink {
pendingConfiguration = null; pendingConfiguration = null;
} }
audioTrackPositionTracker.reset(); audioTrackPositionTracker.reset();
if (Util.SDK_INT >= 24 && onRoutingChangedListener != null) { if (SDK_INT >= 24 && onRoutingChangedListener != null) {
onRoutingChangedListener.release(); onRoutingChangedListener.release();
onRoutingChangedListener = null; onRoutingChangedListener = null;
} }
@ -1735,9 +1734,7 @@ public final class DefaultAudioSink implements AudioSink {
} }
private boolean useAudioTrackPlaybackParams() { private boolean useAudioTrackPlaybackParams() {
return configuration != null return configuration != null && configuration.enableAudioTrackPlaybackParams && SDK_INT >= 23;
&& configuration.enableAudioTrackPlaybackParams
&& Util.SDK_INT >= 23;
} }
/** /**
@ -1841,7 +1838,7 @@ public final class DefaultAudioSink implements AudioSink {
} }
private static boolean isOffloadedPlayback(AudioTrack audioTrack) { private static boolean isOffloadedPlayback(AudioTrack audioTrack) {
return Util.SDK_INT >= 29 && audioTrack.isOffloadedPlayback(); return SDK_INT >= 29 && audioTrack.isOffloadedPlayback();
} }
private static int getFramesPerEncodedSample(@C.Encoding int encoding, ByteBuffer buffer) { private static int getFramesPerEncodedSample(@C.Encoding int encoding, ByteBuffer buffer) {
@ -1902,7 +1899,7 @@ public final class DefaultAudioSink implements AudioSink {
private int writeNonBlockingWithAvSync( private int writeNonBlockingWithAvSync(
AudioTrack audioTrack, ByteBuffer buffer, int size, long presentationTimeUs) { AudioTrack audioTrack, ByteBuffer buffer, int size, long presentationTimeUs) {
if (Util.SDK_INT >= 26) { if (SDK_INT >= 26) {
// The underlying platform AudioTrack writes AV sync headers directly. // The underlying platform AudioTrack writes AV sync headers directly.
return audioTrack.write( return audioTrack.write(
buffer, size, AudioTrack.WRITE_NON_BLOCKING, presentationTimeUs * 1000); buffer, size, AudioTrack.WRITE_NON_BLOCKING, presentationTimeUs * 1000);

View File

@ -15,6 +15,8 @@
*/ */
package androidx.media3.exoplayer.audio; package androidx.media3.exoplayer.audio;
import static android.os.Build.VERSION.SDK_INT;
import android.media.AudioFormat; import android.media.AudioFormat;
import android.media.AudioTrack; import android.media.AudioTrack;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
@ -37,7 +39,7 @@ public class DefaultAudioTrackProvider implements DefaultAudioSink.AudioTrackPro
AudioSink.AudioTrackConfig audioTrackConfig, AudioSink.AudioTrackConfig audioTrackConfig,
AudioAttributes audioAttributes, AudioAttributes audioAttributes,
int audioSessionId) { int audioSessionId) {
if (Util.SDK_INT >= 23) { if (SDK_INT >= 23) {
return createAudioTrackV23(audioTrackConfig, audioAttributes, audioSessionId); return createAudioTrackV23(audioTrackConfig, audioAttributes, audioSessionId);
} else { } else {
return createAudioTrackV21(audioTrackConfig, audioAttributes, audioSessionId); return createAudioTrackV21(audioTrackConfig, audioAttributes, audioSessionId);
@ -61,7 +63,7 @@ public class DefaultAudioTrackProvider implements DefaultAudioSink.AudioTrackPro
.setTransferMode(AudioTrack.MODE_STREAM) .setTransferMode(AudioTrack.MODE_STREAM)
.setBufferSizeInBytes(audioTrackConfig.bufferSize) .setBufferSizeInBytes(audioTrackConfig.bufferSize)
.setSessionId(audioSessionId); .setSessionId(audioSessionId);
if (Util.SDK_INT >= 29) { if (SDK_INT >= 29) {
setOffloadedPlaybackV29(audioTrackBuilder, audioTrackConfig.offload); setOffloadedPlaybackV29(audioTrackBuilder, audioTrackConfig.offload);
} }
return customizeAudioTrackBuilder(audioTrackBuilder).build(); return customizeAudioTrackBuilder(audioTrackBuilder).build();

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.audio; package androidx.media3.exoplayer.audio;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_MAX_INPUT_SIZE_EXCEEDED; import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_MAX_INPUT_SIZE_EXCEEDED;
import static androidx.media3.exoplayer.DecoderReuseEvaluation.REUSE_RESULT_NO; import static androidx.media3.exoplayer.DecoderReuseEvaluation.REUSE_RESULT_NO;
@ -32,6 +33,7 @@ import android.media.MediaFormat;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.util.Pair;
import androidx.annotation.CallSuper; import androidx.annotation.CallSuper;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
@ -43,6 +45,7 @@ import androidx.media3.common.MimeTypes;
import androidx.media3.common.PlaybackException; import androidx.media3.common.PlaybackException;
import androidx.media3.common.PlaybackParameters; import androidx.media3.common.PlaybackParameters;
import androidx.media3.common.audio.AudioProcessor; import androidx.media3.common.audio.AudioProcessor;
import androidx.media3.common.util.CodecSpecificDataUtil;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
import androidx.media3.common.util.MediaFormatUtil; import androidx.media3.common.util.MediaFormatUtil;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
@ -264,7 +267,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
eventHandler, eventHandler,
eventListener, eventListener,
audioSink, audioSink,
Util.SDK_INT >= 35 ? new LoudnessCodecController() : null); SDK_INT >= 35 ? new LoudnessCodecController() : null);
} }
/** /**
@ -610,7 +613,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
if (MimeTypes.AUDIO_RAW.equals(format.sampleMimeType)) { if (MimeTypes.AUDIO_RAW.equals(format.sampleMimeType)) {
// For PCM streams, the encoder passes through int samples despite set to float mode. // For PCM streams, the encoder passes through int samples despite set to float mode.
pcmEncoding = format.pcmEncoding; pcmEncoding = format.pcmEncoding;
} else if (Util.SDK_INT >= 24 && mediaFormat.containsKey(MediaFormat.KEY_PCM_ENCODING)) { } else if (SDK_INT >= 24 && mediaFormat.containsKey(MediaFormat.KEY_PCM_ENCODING)) {
pcmEncoding = mediaFormat.getInteger(MediaFormat.KEY_PCM_ENCODING); pcmEncoding = mediaFormat.getInteger(MediaFormat.KEY_PCM_ENCODING);
} else if (mediaFormat.containsKey(VIVO_BITS_PER_SAMPLE_KEY)) { } else if (mediaFormat.containsKey(VIVO_BITS_PER_SAMPLE_KEY)) {
pcmEncoding = Util.getPcmEncoding(mediaFormat.getInteger(VIVO_BITS_PER_SAMPLE_KEY)); pcmEncoding = Util.getPcmEncoding(mediaFormat.getInteger(VIVO_BITS_PER_SAMPLE_KEY));
@ -649,7 +652,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
} }
} }
try { try {
if (Util.SDK_INT >= 29) { if (SDK_INT >= 29) {
if (isBypassEnabled() if (isBypassEnabled()
&& getConfiguration().offloadModePreferred != AudioSink.OFFLOAD_MODE_DISABLED) { && getConfiguration().offloadModePreferred != AudioSink.OFFLOAD_MODE_DISABLED) {
// TODO(b/280050553): Investigate potential issue where bypass is enabled for passthrough // TODO(b/280050553): Investigate potential issue where bypass is enabled for passthrough
@ -749,7 +752,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
@Override @Override
protected void onRelease() { protected void onRelease() {
audioSink.release(); audioSink.release();
if (Util.SDK_INT >= 35 && loudnessCodecController != null) { if (SDK_INT >= 35 && loudnessCodecController != null) {
loudnessCodecController.release(); loudnessCodecController.release();
} }
} }
@ -908,7 +911,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
audioSink.setAuxEffectInfo(checkNotNull(auxEffectInfo)); audioSink.setAuxEffectInfo(checkNotNull(auxEffectInfo));
break; break;
case MSG_SET_PREFERRED_AUDIO_DEVICE: case MSG_SET_PREFERRED_AUDIO_DEVICE:
if (Util.SDK_INT >= 23) { if (SDK_INT >= 23) {
Api23.setAudioSinkPreferredDevice(audioSink, message); Api23.setAudioSinkPreferredDevice(audioSink, message);
} }
break; break;
@ -930,7 +933,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
@Override @Override
protected void handleInputBufferSupplementalData(DecoderInputBuffer buffer) { protected void handleInputBufferSupplementalData(DecoderInputBuffer buffer) {
if (Util.SDK_INT >= 29 if (SDK_INT >= 29
&& buffer.format != null && buffer.format != null
&& Objects.equals(buffer.format.sampleMimeType, MimeTypes.AUDIO_OPUS) && Objects.equals(buffer.format.sampleMimeType, MimeTypes.AUDIO_OPUS)
&& isBypassEnabled()) { && isBypassEnabled()) {
@ -983,7 +986,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
// Android TV running M, so there's no point requesting a non-default input size. Doing so may // Android TV running M, so there's no point requesting a non-default input size. Doing so may
// cause a native crash, whereas not doing so will cause a more controlled failure when // cause a native crash, whereas not doing so will cause a more controlled failure when
// attempting to fill an input buffer. See: https://github.com/google/ExoPlayer/issues/4057. // attempting to fill an input buffer. See: https://github.com/google/ExoPlayer/issues/4057.
if (Util.SDK_INT < 24 && !(Util.SDK_INT == 23 && Util.isTv(context))) { if (SDK_INT < 24 && !(SDK_INT == 23 && Util.isTv(context))) {
return Format.NO_VALUE; return Format.NO_VALUE;
} }
} }
@ -1013,27 +1016,34 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
// Set codec max values. // Set codec max values.
MediaFormatUtil.maybeSetInteger(mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE, codecMaxInputSize); MediaFormatUtil.maybeSetInteger(mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE, codecMaxInputSize);
// Set codec configuration values. // Set codec configuration values.
if (Util.SDK_INT >= 23) { if (SDK_INT >= 23) {
mediaFormat.setInteger(MediaFormat.KEY_PRIORITY, 0 /* realtime priority */); mediaFormat.setInteger(MediaFormat.KEY_PRIORITY, 0 /* realtime priority */);
if (codecOperatingRate != CODEC_OPERATING_RATE_UNSET && !deviceDoesntSupportOperatingRate()) { if (codecOperatingRate != CODEC_OPERATING_RATE_UNSET && !deviceDoesntSupportOperatingRate()) {
mediaFormat.setFloat(MediaFormat.KEY_OPERATING_RATE, codecOperatingRate); mediaFormat.setFloat(MediaFormat.KEY_OPERATING_RATE, codecOperatingRate);
} }
} }
if (Util.SDK_INT <= 28 && MimeTypes.AUDIO_AC4.equals(format.sampleMimeType)) { if (MimeTypes.AUDIO_AC4.equals(format.sampleMimeType)) {
// On some older builds, the AC-4 decoder expects to receive samples formatted as raw frames Pair<Integer, Integer> profileLevel = CodecSpecificDataUtil.getCodecProfileAndLevel(format);
// not sync frames. Set a format key to override this. if (profileLevel != null) {
mediaFormat.setInteger("ac4-is-sync", 1); MediaFormatUtil.maybeSetInteger(mediaFormat, MediaFormat.KEY_PROFILE, profileLevel.first);
MediaFormatUtil.maybeSetInteger(mediaFormat, MediaFormat.KEY_LEVEL, profileLevel.second);
}
if (SDK_INT <= 28) {
// On some older builds, the AC-4 decoder expects to receive samples formatted as raw frames
// not sync frames. Set a format key to override this.
mediaFormat.setInteger("ac4-is-sync", 1);
}
} }
if (Util.SDK_INT >= 24 if (SDK_INT >= 24
&& audioSink.getFormatSupport( && audioSink.getFormatSupport(
Util.getPcmFormat(C.ENCODING_PCM_FLOAT, format.channelCount, format.sampleRate)) Util.getPcmFormat(C.ENCODING_PCM_FLOAT, format.channelCount, format.sampleRate))
== AudioSink.SINK_FORMAT_SUPPORTED_DIRECTLY) { == AudioSink.SINK_FORMAT_SUPPORTED_DIRECTLY) {
mediaFormat.setInteger(MediaFormat.KEY_PCM_ENCODING, AudioFormat.ENCODING_PCM_FLOAT); mediaFormat.setInteger(MediaFormat.KEY_PCM_ENCODING, AudioFormat.ENCODING_PCM_FLOAT);
} }
if (Util.SDK_INT >= 32) { if (SDK_INT >= 32) {
mediaFormat.setInteger(MediaFormat.KEY_MAX_OUTPUT_CHANNEL_COUNT, 99); mediaFormat.setInteger(MediaFormat.KEY_MAX_OUTPUT_CHANNEL_COUNT, 99);
} }
if (Util.SDK_INT >= 35) { if (SDK_INT >= 35) {
mediaFormat.setInteger(MediaFormat.KEY_IMPORTANCE, max(0, -rendererPriority)); mediaFormat.setInteger(MediaFormat.KEY_IMPORTANCE, max(0, -rendererPriority));
} }
return mediaFormat; return mediaFormat;
@ -1041,7 +1051,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
private void setAudioSessionId(int audioSessionId) { private void setAudioSessionId(int audioSessionId) {
audioSink.setAudioSessionId(audioSessionId); audioSink.setAudioSessionId(audioSessionId);
if (Util.SDK_INT >= 35 && loudnessCodecController != null) { if (SDK_INT >= 35 && loudnessCodecController != null) {
loudnessCodecController.setAudioSessionId(audioSessionId); loudnessCodecController.setAudioSessionId(audioSessionId);
} }
} }
@ -1052,7 +1062,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
// If codec is null, then the importance will be set when initializing the codec. // If codec is null, then the importance will be set when initializing the codec.
return; return;
} }
if (Util.SDK_INT >= 35) { if (SDK_INT >= 35) {
Bundle codecParameters = new Bundle(); Bundle codecParameters = new Bundle();
codecParameters.putInt(MediaFormat.KEY_IMPORTANCE, max(0, -rendererPriority)); codecParameters.putInt(MediaFormat.KEY_IMPORTANCE, max(0, -rendererPriority));
codec.setParameters(codecParameters); codec.setParameters(codecParameters);
@ -1077,8 +1087,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
* <p>See <a href="https://github.com/google/ExoPlayer/issues/5821">GitHub issue #5821</a>. * <p>See <a href="https://github.com/google/ExoPlayer/issues/5821">GitHub issue #5821</a>.
*/ */
private static boolean deviceDoesntSupportOperatingRate() { private static boolean deviceDoesntSupportOperatingRate() {
return Util.SDK_INT == 23 return SDK_INT == 23 && ("ZTE B2017G".equals(Build.MODEL) || "AXON 7 mini".equals(Build.MODEL));
&& ("ZTE B2017G".equals(Build.MODEL) || "AXON 7 mini".equals(Build.MODEL));
} }
/** /**
@ -1089,7 +1098,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
*/ */
private static boolean codecNeedsDiscardChannelsWorkaround(String codecName) { private static boolean codecNeedsDiscardChannelsWorkaround(String codecName) {
// The workaround applies to Samsung Galaxy S6 and Samsung Galaxy S7. // The workaround applies to Samsung Galaxy S6 and Samsung Galaxy S7.
return Util.SDK_INT < 24 return SDK_INT < 24
&& "OMX.SEC.aac.dec".equals(codecName) && "OMX.SEC.aac.dec".equals(codecName)
&& "samsung".equals(Build.MANUFACTURER) && "samsung".equals(Build.MANUFACTURER)
&& (Build.DEVICE.startsWith("zeroflte") && (Build.DEVICE.startsWith("zeroflte")

View File

@ -15,6 +15,8 @@
*/ */
package androidx.media3.exoplayer.drm; package androidx.media3.exoplayer.drm;
import static android.os.Build.VERSION.SDK_INT;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import org.json.JSONArray; import org.json.JSONArray;
@ -35,7 +37,7 @@ import org.json.JSONObject;
* @return The adjusted request data. * @return The adjusted request data.
*/ */
public static byte[] adjustRequestData(byte[] request) { public static byte[] adjustRequestData(byte[] request) {
if (Util.SDK_INT >= 27) { if (SDK_INT >= 27) {
return request; return request;
} }
// Prior to O-MR1 the ClearKey CDM encoded the values in the "kids" array using Base64 encoding // Prior to O-MR1 the ClearKey CDM encoded the values in the "kids" array using Base64 encoding
@ -53,7 +55,7 @@ import org.json.JSONObject;
* @return The adjusted response data. * @return The adjusted response data.
*/ */
public static byte[] adjustResponseData(byte[] response) { public static byte[] adjustResponseData(byte[] response) {
if (Util.SDK_INT >= 27) { if (SDK_INT >= 27) {
return response; return response;
} }
// Prior to O-MR1 the ClearKey CDM expected Base64 encoding rather than Base64Url encoding for // Prior to O-MR1 the ClearKey CDM expected Base64 encoding rather than Base64Url encoding for

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.drm; package androidx.media3.exoplayer.drm;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
@ -593,7 +594,7 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
} else if (C.CENC_TYPE_cbcs.equals(schemeType)) { } else if (C.CENC_TYPE_cbcs.equals(schemeType)) {
// Support for cbcs (AES-CBC with pattern encryption) was added in API 24. However, the // Support for cbcs (AES-CBC with pattern encryption) was added in API 24. However, the
// implementation was not stable until API 25. // implementation was not stable until API 25.
return Util.SDK_INT >= 25; return SDK_INT >= 25;
} else if (C.CENC_TYPE_cbc1.equals(schemeType) || C.CENC_TYPE_cens.equals(schemeType)) { } else if (C.CENC_TYPE_cbc1.equals(schemeType) || C.CENC_TYPE_cens.equals(schemeType)) {
// Support for cbc1 (AES-CTR with pattern encryption) and cens (AES-CBC without pattern // Support for cbc1 (AES-CTR with pattern encryption) and cens (AES-CBC without pattern
// encryption) was also added in API 24 and made stable from API 25, however support was // encryption) was also added in API 24 and made stable from API 25, however support was

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.drm; package androidx.media3.exoplayer.drm;
import static android.os.Build.VERSION.SDK_INT;
import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE; import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.METHOD;
@ -90,7 +91,7 @@ public final class DrmUtil {
String diagnosticsInfo = ((MediaDrm.MediaDrmStateException) exception).getDiagnosticInfo(); String diagnosticsInfo = ((MediaDrm.MediaDrmStateException) exception).getDiagnosticInfo();
int drmErrorCode = Util.getErrorCodeFromPlatformDiagnosticsInfo(diagnosticsInfo); int drmErrorCode = Util.getErrorCodeFromPlatformDiagnosticsInfo(diagnosticsInfo);
return Util.getErrorCodeForMediaDrmErrorCode(drmErrorCode); return Util.getErrorCodeForMediaDrmErrorCode(drmErrorCode);
} else if (Util.SDK_INT >= 23 && Api23.isMediaDrmResetException(exception)) { } else if (SDK_INT >= 23 && Api23.isMediaDrmResetException(exception)) {
return PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR; return PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR;
} else if (exception instanceof NotProvisionedException } else if (exception instanceof NotProvisionedException
|| isFailureToConstructNotProvisionedException(exception)) { || isFailureToConstructNotProvisionedException(exception)) {
@ -122,7 +123,7 @@ public final class DrmUtil {
* See b/291440132. * See b/291440132.
*/ */
public static boolean isFailureToConstructNotProvisionedException(@Nullable Throwable e) { public static boolean isFailureToConstructNotProvisionedException(@Nullable Throwable e) {
return Util.SDK_INT == 34 return SDK_INT == 34
&& e instanceof NoSuchMethodError && e instanceof NoSuchMethodError
&& e.getMessage() != null && e.getMessage() != null
&& e.getMessage().contains("Landroid/media/NotProvisionedException;.<init>("); && e.getMessage().contains("Landroid/media/NotProvisionedException;.<init>(");
@ -133,7 +134,7 @@ public final class DrmUtil {
* See b/291440132. * See b/291440132.
*/ */
public static boolean isFailureToConstructResourceBusyException(@Nullable Throwable e) { public static boolean isFailureToConstructResourceBusyException(@Nullable Throwable e) {
return Util.SDK_INT == 34 return SDK_INT == 34
&& e instanceof NoSuchMethodError && e instanceof NoSuchMethodError
&& e.getMessage() != null && e.getMessage() != null
&& e.getMessage().contains("Landroid/media/ResourceBusyException;.<init>("); && e.getMessage().contains("Landroid/media/ResourceBusyException;.<init>(");

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.drm; package androidx.media3.exoplayer.drm;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
@ -39,7 +40,6 @@ import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
import androidx.media3.common.util.ParsableByteArray; import androidx.media3.common.util.ParsableByteArray;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.analytics.PlayerId; import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.extractor.mp4.PsshAtomUtil; import androidx.media3.extractor.mp4.PsshAtomUtil;
import androidx.media3.extractor.mp4.PsshAtomUtil.PsshAtom; import androidx.media3.extractor.mp4.PsshAtomUtil.PsshAtom;
@ -144,7 +144,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
@RequiresApi(23) @RequiresApi(23)
public void setOnKeyStatusChangeListener( public void setOnKeyStatusChangeListener(
@Nullable ExoMediaDrm.OnKeyStatusChangeListener listener) { @Nullable ExoMediaDrm.OnKeyStatusChangeListener listener) {
if (Util.SDK_INT < 23) { if (SDK_INT < 23) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -172,7 +172,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
@Override @Override
@RequiresApi(23) @RequiresApi(23)
public void setOnExpirationUpdateListener(@Nullable OnExpirationUpdateListener listener) { public void setOnExpirationUpdateListener(@Nullable OnExpirationUpdateListener listener) {
if (Util.SDK_INT < 23) { if (SDK_INT < 23) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -199,7 +199,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
@UnstableApi @UnstableApi
@Override @Override
public void setPlayerIdForSession(byte[] sessionId, PlayerId playerId) { public void setPlayerIdForSession(byte[] sessionId, PlayerId playerId) {
if (Util.SDK_INT >= 31) { if (SDK_INT >= 31) {
try { try {
Api31.setLogSessionIdOnMediaDrmSession(mediaDrm, sessionId, playerId); Api31.setLogSessionIdOnMediaDrmSession(mediaDrm, sessionId, playerId);
} catch (UnsupportedOperationException e) { } catch (UnsupportedOperationException e) {
@ -238,8 +238,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
} }
@KeyRequest.RequestType @KeyRequest.RequestType
int requestType = int requestType = SDK_INT >= 23 ? request.getRequestType() : KeyRequest.REQUEST_TYPE_UNKNOWN;
Util.SDK_INT >= 23 ? request.getRequestType() : KeyRequest.REQUEST_TYPE_UNKNOWN;
return new KeyRequest(requestData, licenseServerUrl, requestType); return new KeyRequest(requestData, licenseServerUrl, requestType);
} }
@ -248,7 +247,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
if (MOCK_LA_URL.equals(licenseServerUrl)) { if (MOCK_LA_URL.equals(licenseServerUrl)) {
return ""; return "";
} }
if (Util.SDK_INT >= 33 && "https://default.url".equals(licenseServerUrl)) { if (SDK_INT >= 33 && "https://default.url".equals(licenseServerUrl)) {
// Work around b/247808112 // Work around b/247808112
String pluginVersion = getPropertyString("version"); String pluginVersion = getPropertyString("version");
if (Objects.equals(pluginVersion, "1.2") || Objects.equals(pluginVersion, "aidl-1")) { if (Objects.equals(pluginVersion, "1.2") || Objects.equals(pluginVersion, "aidl-1")) {
@ -293,7 +292,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
@Override @Override
public boolean requiresSecureDecoder(byte[] sessionId, String mimeType) { public boolean requiresSecureDecoder(byte[] sessionId, String mimeType) {
boolean result; boolean result;
if (Util.SDK_INT >= 31 && isMediaDrmRequiresSecureDecoderImplemented()) { if (SDK_INT >= 31 && isMediaDrmRequiresSecureDecoderImplemented()) {
result = result =
Api31.requiresSecureDecoder(mediaDrm, mimeType, mediaDrm.getSecurityLevel(sessionId)); Api31.requiresSecureDecoder(mediaDrm, mimeType, mediaDrm.getSecurityLevel(sessionId));
} else { } else {
@ -341,7 +340,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
@UnstableApi @UnstableApi
@RequiresApi(29) @RequiresApi(29)
public void removeOfflineLicense(byte[] keySetId) { public void removeOfflineLicense(byte[] keySetId) {
if (Util.SDK_INT < 29) { if (SDK_INT < 29) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
mediaDrm.removeOfflineLicense(keySetId); mediaDrm.removeOfflineLicense(keySetId);
@ -351,7 +350,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
@UnstableApi @UnstableApi
@RequiresApi(29) @RequiresApi(29)
public List<byte[]> getOfflineLicenseKeySetIds() { public List<byte[]> getOfflineLicenseKeySetIds() {
if (Util.SDK_INT < 29) { if (SDK_INT < 29) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
return mediaDrm.getOfflineLicenseKeySetIds(); return mediaDrm.getOfflineLicenseKeySetIds();
@ -361,7 +360,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
@Override @Override
@Nullable @Nullable
public PersistableBundle getMetrics() { public PersistableBundle getMetrics() {
if (Util.SDK_INT < 28) { if (SDK_INT < 28) {
return null; return null;
} }
return mediaDrm.getMetrics(); return mediaDrm.getMetrics();
@ -429,7 +428,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
return schemeDatas.get(0); return schemeDatas.get(0);
} }
if (Util.SDK_INT >= 28 && schemeDatas.size() > 1) { if (SDK_INT >= 28 && schemeDatas.size() > 1) {
// For API level 28 and above, concatenate multiple PSSH scheme datas if possible. // For API level 28 and above, concatenate multiple PSSH scheme datas if possible.
SchemeData firstSchemeData = schemeDatas.get(0); SchemeData firstSchemeData = schemeDatas.get(0);
int concatenatedDataLength = 0; int concatenatedDataLength = 0;
@ -466,9 +465,9 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
for (int i = 0; i < schemeDatas.size(); i++) { for (int i = 0; i < schemeDatas.size(); i++) {
SchemeData schemeData = schemeDatas.get(i); SchemeData schemeData = schemeDatas.get(i);
int version = PsshAtomUtil.parseVersion(Assertions.checkNotNull(schemeData.data)); int version = PsshAtomUtil.parseVersion(Assertions.checkNotNull(schemeData.data));
if (Util.SDK_INT < 23 && version == 0) { if (SDK_INT < 23 && version == 0) {
return schemeData; return schemeData;
} else if (Util.SDK_INT >= 23 && version == 1) { } else if (SDK_INT >= 23 && version == 1) {
return schemeData; return schemeData;
} }
} }
@ -508,7 +507,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
// that only provides V1 PSSH atoms. API levels 23 and above understand V0 and V1 PSSH atoms, // that only provides V1 PSSH atoms. API levels 23 and above understand V0 and V1 PSSH atoms,
// and so we do not extract the data. // and so we do not extract the data.
// Some Amazon devices also require data to be extracted from the PSSH atom for PlayReady. // Some Amazon devices also require data to be extracted from the PSSH atom for PlayReady.
if ((Util.SDK_INT < 23 && C.WIDEVINE_UUID.equals(uuid)) if ((SDK_INT < 23 && C.WIDEVINE_UUID.equals(uuid))
|| (C.PLAYREADY_UUID.equals(uuid) || (C.PLAYREADY_UUID.equals(uuid)
&& "Amazon".equals(Build.MANUFACTURER) && "Amazon".equals(Build.MANUFACTURER)
&& ("AFTB".equals(Build.MODEL) // Fire TV Gen 1 && ("AFTB".equals(Build.MODEL) // Fire TV Gen 1
@ -526,7 +525,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
private static String adjustRequestMimeType(UUID uuid, String mimeType) { private static String adjustRequestMimeType(UUID uuid, String mimeType) {
// Prior to API level 26 the ClearKey CDM only accepted "cenc" as the scheme for MP4. // Prior to API level 26 the ClearKey CDM only accepted "cenc" as the scheme for MP4.
if (Util.SDK_INT < 26 if (SDK_INT < 26
&& C.CLEARKEY_UUID.equals(uuid) && C.CLEARKEY_UUID.equals(uuid)
&& (MimeTypes.VIDEO_MP4.equals(mimeType) || MimeTypes.AUDIO_MP4.equals(mimeType))) { && (MimeTypes.VIDEO_MP4.equals(mimeType) || MimeTypes.AUDIO_MP4.equals(mimeType))) {
return CENC_SCHEME_MIME_TYPE; return CENC_SCHEME_MIME_TYPE;
@ -543,7 +542,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
private static boolean cdmRequiresCommonPsshUuid(UUID uuid) { private static boolean cdmRequiresCommonPsshUuid(UUID uuid) {
// ClearKey had to be accessed using the Common PSSH UUID prior to API level 27. // ClearKey had to be accessed using the Common PSSH UUID prior to API level 27.
return Util.SDK_INT < 27 && Objects.equals(uuid, C.CLEARKEY_UUID); return SDK_INT < 27 && Objects.equals(uuid, C.CLEARKEY_UUID);
} }
private static void forceWidevineL3(MediaDrm mediaDrm) { private static void forceWidevineL3(MediaDrm mediaDrm) {

View File

@ -16,6 +16,7 @@
package androidx.media3.exoplayer.mediacodec; package androidx.media3.exoplayer.mediacodec;
import static android.os.Build.VERSION.SDK_INT;
import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.ElementType.TYPE_USE;
import android.media.MediaCodec; import android.media.MediaCodec;
@ -35,7 +36,6 @@ import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.TraceUtil; import androidx.media3.common.util.TraceUtil;
import androidx.media3.common.util.Util;
import androidx.media3.decoder.CryptoInfo; import androidx.media3.decoder.CryptoInfo;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import java.io.IOException; import java.io.IOException;
@ -129,7 +129,7 @@ import java.nio.ByteBuffer;
TraceUtil.endSection(); TraceUtil.endSection();
if (configuration.surface == null if (configuration.surface == null
&& configuration.codecInfo.detachedSurfaceSupported && configuration.codecInfo.detachedSurfaceSupported
&& Util.SDK_INT >= 35) { && SDK_INT >= 35) {
flags |= MediaCodec.CONFIGURE_FLAG_DETACHED_SURFACE; flags |= MediaCodec.CONFIGURE_FLAG_DETACHED_SURFACE;
} }
codecAdapter.initialize( codecAdapter.initialize(
@ -147,11 +147,11 @@ import java.nio.ByteBuffer;
@ChecksSdkIntAtLeast(api = 34) @ChecksSdkIntAtLeast(api = 34)
private static boolean useSynchronousBufferQueueingWithAsyncCryptoFlag(Format format) { private static boolean useSynchronousBufferQueueingWithAsyncCryptoFlag(Format format) {
if (Util.SDK_INT < 34) { if (SDK_INT < 34) {
return false; return false;
} }
// CONFIGURE_FLAG_USE_CRYPTO_ASYNC only works for audio on API 35+ (see b/316565675). // CONFIGURE_FLAG_USE_CRYPTO_ASYNC only works for audio on API 35+ (see b/316565675).
return Util.SDK_INT >= 35 || MimeTypes.isVideo(format.sampleMimeType); return SDK_INT >= 35 || MimeTypes.isVideo(format.sampleMimeType);
} }
} }
@ -198,7 +198,7 @@ import java.nio.ByteBuffer;
TraceUtil.beginSection("startCodec"); TraceUtil.beginSection("startCodec");
codec.start(); codec.start();
TraceUtil.endSection(); TraceUtil.endSection();
if (Util.SDK_INT >= 35 && loudnessCodecController != null) { if (SDK_INT >= 35 && loudnessCodecController != null) {
loudnessCodecController.addMediaCodec(codec); loudnessCodecController.addMediaCodec(codec);
} }
state = STATE_INITIALIZED; state = STATE_INITIALIZED;
@ -289,11 +289,11 @@ import java.nio.ByteBuffer;
// MediaCodec.release() returns too early before fully detaching a Surface, and a // MediaCodec.release() returns too early before fully detaching a Surface, and a
// subsequent MediaCodec.configure() call using the same Surface then fails. See // subsequent MediaCodec.configure() call using the same Surface then fails. See
// https://github.com/google/ExoPlayer/issues/8696 and b/191966399. // https://github.com/google/ExoPlayer/issues/8696 and b/191966399.
if (Util.SDK_INT >= 30 && Util.SDK_INT < 33) { if (SDK_INT >= 30 && SDK_INT < 33) {
codec.stop(); codec.stop();
} }
} finally { } finally {
if (Util.SDK_INT >= 35 && loudnessCodecController != null) { if (SDK_INT >= 35 && loudnessCodecController != null) {
loudnessCodecController.removeMediaCodec(codec); loudnessCodecController.removeMediaCodec(codec);
} }
codec.release(); codec.release();

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.mediacodec; package androidx.media3.exoplayer.mediacodec;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.annotation.VisibleForTesting.NONE; import static androidx.annotation.VisibleForTesting.NONE;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Util.castNonNull; import static androidx.media3.common.util.Util.castNonNull;
@ -30,7 +31,6 @@ import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.media3.common.util.ConditionVariable; import androidx.media3.common.util.ConditionVariable;
import androidx.media3.common.util.NullableType; import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.Util;
import androidx.media3.decoder.CryptoInfo; import androidx.media3.decoder.CryptoInfo;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Arrays; import java.util.Arrays;
@ -298,7 +298,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
frameworkCryptoInfo.key = checkNotNull(copy(cryptoInfo.key, frameworkCryptoInfo.key)); frameworkCryptoInfo.key = checkNotNull(copy(cryptoInfo.key, frameworkCryptoInfo.key));
frameworkCryptoInfo.iv = checkNotNull(copy(cryptoInfo.iv, frameworkCryptoInfo.iv)); frameworkCryptoInfo.iv = checkNotNull(copy(cryptoInfo.iv, frameworkCryptoInfo.iv));
frameworkCryptoInfo.mode = cryptoInfo.mode; frameworkCryptoInfo.mode = cryptoInfo.mode;
if (Util.SDK_INT >= 24) { if (SDK_INT >= 24) {
android.media.MediaCodec.CryptoInfo.Pattern pattern = android.media.MediaCodec.CryptoInfo.Pattern pattern =
new android.media.MediaCodec.CryptoInfo.Pattern( new android.media.MediaCodec.CryptoInfo.Pattern(
cryptoInfo.encryptedBlocks, cryptoInfo.clearBlocks); cryptoInfo.encryptedBlocks, cryptoInfo.clearBlocks);

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.mediacodec; package androidx.media3.exoplayer.mediacodec;
import static android.os.Build.VERSION.SDK_INT;
import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.ElementType.TYPE_USE;
import android.content.Context; import android.content.Context;
@ -146,7 +147,7 @@ public final class DefaultMediaCodecAdapterFactory implements MediaCodecAdapter.
@Override @Override
public MediaCodecAdapter createAdapter(MediaCodecAdapter.Configuration configuration) public MediaCodecAdapter createAdapter(MediaCodecAdapter.Configuration configuration)
throws IOException { throws IOException {
if (Util.SDK_INT >= 23 if (SDK_INT >= 23
&& (asynchronousMode == MODE_ENABLED && (asynchronousMode == MODE_ENABLED
|| (asynchronousMode == MODE_DEFAULT && shouldUseAsynchronousAdapterInDefaultMode()))) { || (asynchronousMode == MODE_DEFAULT && shouldUseAsynchronousAdapterInDefaultMode()))) {
int trackType = MimeTypes.getTrackType(configuration.format.sampleMimeType); int trackType = MimeTypes.getTrackType(configuration.format.sampleMimeType);
@ -166,14 +167,14 @@ public final class DefaultMediaCodecAdapterFactory implements MediaCodecAdapter.
} }
private boolean shouldUseAsynchronousAdapterInDefaultMode() { private boolean shouldUseAsynchronousAdapterInDefaultMode() {
if (Util.SDK_INT >= 31) { if (SDK_INT >= 31) {
// Asynchronous codec interactions started to be reliable for all devices on API 31+. // Asynchronous codec interactions started to be reliable for all devices on API 31+.
return true; return true;
} }
// Allow additional devices that work reliably with the asynchronous adapter and show // Allow additional devices that work reliably with the asynchronous adapter and show
// performance problems when not using it. // performance problems when not using it.
if (context != null if (context != null
&& Util.SDK_INT >= 28 && SDK_INT >= 28
&& context.getPackageManager().hasSystemFeature("com.amazon.hardware.tv_screen")) { && context.getPackageManager().hasSystemFeature("com.amazon.hardware.tv_screen")) {
return true; return true;
} }

View File

@ -15,6 +15,8 @@
*/ */
package androidx.media3.exoplayer.mediacodec; package androidx.media3.exoplayer.mediacodec;
import static android.os.Build.VERSION.SDK_INT;
import android.media.MediaCodec; import android.media.MediaCodec;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
@ -43,7 +45,7 @@ public class MediaCodecDecoderException extends DecoderException {
? ((MediaCodec.CodecException) cause).getDiagnosticInfo() ? ((MediaCodec.CodecException) cause).getDiagnosticInfo()
: null; : null;
errorCode = errorCode =
Util.SDK_INT >= 23 SDK_INT >= 23
? getErrorCodeV23(cause) ? getErrorCodeV23(cause)
: Util.getErrorCodeFromPlatformDiagnosticsInfo(diagnosticInfo); : Util.getErrorCodeFromPlatformDiagnosticsInfo(diagnosticInfo);
} }

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.mediacodec; package androidx.media3.exoplayer.mediacodec;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_AUDIO_CHANNEL_COUNT_CHANGED; import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_AUDIO_CHANNEL_COUNT_CHANGED;
import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_AUDIO_ENCODING_CHANGED; import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_AUDIO_ENCODING_CHANGED;
import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_AUDIO_SAMPLE_RATE_CHANGED; import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_AUDIO_SAMPLE_RATE_CHANGED;
@ -247,7 +248,7 @@ public final class MediaCodecInfo {
* @see CodecCapabilities#getMaxSupportedInstances() * @see CodecCapabilities#getMaxSupportedInstances()
*/ */
public int getMaxSupportedInstances() { public int getMaxSupportedInstances() {
if (Util.SDK_INT < 23 || capabilities == null) { if (SDK_INT < 23 || capabilities == null) {
return MAX_SUPPORTED_INSTANCES_UNKNOWN; return MAX_SUPPORTED_INSTANCES_UNKNOWN;
} }
return getMaxSupportedInstancesV23(capabilities); return getMaxSupportedInstancesV23(capabilities);
@ -355,7 +356,7 @@ public final class MediaCodecInfo {
} }
CodecProfileLevel[] profileLevels = getProfileLevels(); CodecProfileLevel[] profileLevels = getProfileLevels();
if (Util.SDK_INT <= 23 && MimeTypes.VIDEO_VP9.equals(mimeType) && profileLevels.length == 0) { if (SDK_INT <= 23 && MimeTypes.VIDEO_VP9.equals(mimeType) && profileLevels.length == 0) {
// Some older devices don't report profile levels for VP9. Estimate them using other data in // Some older devices don't report profile levels for VP9. Estimate them using other data in
// the codec capabilities. // the codec capabilities.
profileLevels = estimateLegacyVp9ProfileLevels(capabilities); profileLevels = estimateLegacyVp9ProfileLevels(capabilities);
@ -379,13 +380,13 @@ public final class MediaCodecInfo {
// exists. // exists.
return !Objects.equals(format.sampleMimeType, MimeTypes.AUDIO_FLAC) return !Objects.equals(format.sampleMimeType, MimeTypes.AUDIO_FLAC)
|| format.pcmEncoding != C.ENCODING_PCM_32BIT || format.pcmEncoding != C.ENCODING_PCM_32BIT
|| Util.SDK_INT >= 34 || SDK_INT >= 34
|| !name.equals("c2.android.flac.decoder"); || !name.equals("c2.android.flac.decoder");
} }
/** Whether the codec handles HDR10+ out-of-band metadata. */ /** Whether the codec handles HDR10+ out-of-band metadata. */
public boolean isHdr10PlusOutOfBandMetadataSupported() { public boolean isHdr10PlusOutOfBandMetadataSupported() {
if (Util.SDK_INT >= 29 && MimeTypes.VIDEO_VP9.equals(mimeType)) { if (SDK_INT >= 29 && MimeTypes.VIDEO_VP9.equals(mimeType)) {
for (CodecProfileLevel capabilities : getProfileLevels()) { for (CodecProfileLevel capabilities : getProfileLevels()) {
if (capabilities.profile == CodecProfileLevel.VP9Profile2HDR10Plus) { if (capabilities.profile == CodecProfileLevel.VP9Profile2HDR10Plus) {
return true; return true;
@ -531,7 +532,7 @@ public final class MediaCodecInfo {
return false; return false;
} }
if (Util.SDK_INT >= 29) { if (SDK_INT >= 29) {
@MediaCodecPerformancePointCoverageProvider.PerformancePointCoverageResult @MediaCodecPerformancePointCoverageProvider.PerformancePointCoverageResult
int evaluation = int evaluation =
MediaCodecPerformancePointCoverageProvider.areResolutionAndFrameRateCovered( MediaCodecPerformancePointCoverageProvider.areResolutionAndFrameRateCovered(
@ -657,7 +658,7 @@ public final class MediaCodecInfo {
} }
private static int adjustMaxInputChannelCount(String name, String mimeType, int maxChannelCount) { private static int adjustMaxInputChannelCount(String name, String mimeType, int maxChannelCount) {
if (maxChannelCount > 1 || (Util.SDK_INT >= 26 && maxChannelCount > 0)) { if (maxChannelCount > 1 || (SDK_INT >= 26 && maxChannelCount > 0)) {
// The maximum channel count looks like it's been set correctly. // The maximum channel count looks like it's been set correctly.
return maxChannelCount; return maxChannelCount;
} }
@ -710,7 +711,7 @@ public final class MediaCodecInfo {
} }
private static boolean isDetachedSurfaceSupported(@Nullable CodecCapabilities capabilities) { private static boolean isDetachedSurfaceSupported(@Nullable CodecCapabilities capabilities) {
return Util.SDK_INT >= 35 return SDK_INT >= 35
&& capabilities != null && capabilities != null
&& capabilities.isFeatureSupported(CodecCapabilities.FEATURE_DetachedSurface) && capabilities.isFeatureSupported(CodecCapabilities.FEATURE_DetachedSurface)
&& !needsDetachedSurfaceUnsupportedWorkaround(); && !needsDetachedSurfaceUnsupportedWorkaround();
@ -735,7 +736,7 @@ public final class MediaCodecInfo {
if (!capabilities.areSizeAndRateSupported(width, height, floorFrameRate)) { if (!capabilities.areSizeAndRateSupported(width, height, floorFrameRate)) {
return false; return false;
} }
if (Util.SDK_INT < 24) { if (SDK_INT < 24) {
return true; return true;
} }
@Nullable @Nullable
@ -761,8 +762,8 @@ public final class MediaCodecInfo {
} }
/** /**
* Called on devices with {@link Util#SDK_INT} 23 and below, for VP9 decoders whose {@link * Called on devices with {@link Build.VERSION#SDK_INT} 23 and below, for VP9 decoders whose
* CodecCapabilities} do not correctly report profile levels. The returned {@link * {@link CodecCapabilities} do not correctly report profile levels. The returned {@link
* CodecProfileLevel CodecProfileLevels} are estimated based on other data in the {@link * CodecProfileLevel CodecProfileLevels} are estimated based on other data in the {@link
* CodecCapabilities}. * CodecCapabilities}.
* *
@ -818,7 +819,7 @@ public final class MediaCodecInfo {
* @return True if the decoder is known to fail when adapting. * @return True if the decoder is known to fail when adapting.
*/ */
private static boolean needsDisableAdaptationWorkaround(String name) { private static boolean needsDisableAdaptationWorkaround(String name) {
return Util.SDK_INT <= 22 return SDK_INT <= 22
&& ("ODROID-XU3".equals(Build.MODEL) || "Nexus 10".equals(Build.MODEL)) && ("ODROID-XU3".equals(Build.MODEL) || "Nexus 10".equals(Build.MODEL))
&& ("OMX.Exynos.AVC.Decoder".equals(name) || "OMX.Exynos.AVC.Decoder.secure".equals(name)); && ("OMX.Exynos.AVC.Decoder".equals(name) || "OMX.Exynos.AVC.Decoder.secure".equals(name));
} }

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.mediacodec; package androidx.media3.exoplayer.mediacodec;
import static android.os.Build.VERSION.SDK_INT;
import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.ElementType.TYPE_USE;
import android.media.MediaCodecInfo.VideoCapabilities; import android.media.MediaCodecInfo.VideoCapabilities;
@ -23,7 +24,6 @@ import androidx.annotation.IntDef;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Util;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -85,8 +85,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
*/ */
public static @PerformancePointCoverageResult int areResolutionAndFrameRateCovered( public static @PerformancePointCoverageResult int areResolutionAndFrameRateCovered(
VideoCapabilities videoCapabilities, int width, int height, double frameRate) { VideoCapabilities videoCapabilities, int width, int height, double frameRate) {
if (Util.SDK_INT < 29 if (SDK_INT < 29 || (shouldIgnorePerformancePoints != null && shouldIgnorePerformancePoints)) {
|| (shouldIgnorePerformancePoints != null && shouldIgnorePerformancePoints)) {
return COVERAGE_RESULT_NO_PERFORMANCE_POINTS_UNSUPPORTED; return COVERAGE_RESULT_NO_PERFORMANCE_POINTS_UNSUPPORTED;
} }
@ -131,7 +130,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* Checks if the CDD-requirement to support H264 720p at 60 fps is covered by PerformancePoints. * Checks if the CDD-requirement to support H264 720p at 60 fps is covered by PerformancePoints.
*/ */
private static boolean shouldIgnorePerformancePoints() { private static boolean shouldIgnorePerformancePoints() {
if (Util.SDK_INT >= 35) { if (SDK_INT >= 35) {
// The same check as below is tested in CTS and we should get reliable results from API 35. // The same check as below is tested in CTS and we should get reliable results from API 35.
return false; return false;
} }

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.mediacodec; package androidx.media3.exoplayer.mediacodec;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Assertions.checkStateNotNull; import static androidx.media3.common.util.Assertions.checkStateNotNull;
@ -945,9 +946,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
return true; return true;
} }
if (codecDrainAction == DRAIN_ACTION_FLUSH_AND_UPDATE_DRM_SESSION) { if (codecDrainAction == DRAIN_ACTION_FLUSH_AND_UPDATE_DRM_SESSION) {
checkState(Util.SDK_INT >= 23); // Implied by DRAIN_ACTION_FLUSH_AND_UPDATE_DRM_SESSION checkState(SDK_INT >= 23); // Implied by DRAIN_ACTION_FLUSH_AND_UPDATE_DRM_SESSION
// Needed to keep lint happy (it doesn't understand the checkState call alone) // Needed to keep lint happy (it doesn't understand the checkState call alone)
if (Util.SDK_INT >= 23) { if (SDK_INT >= 23) {
try { try {
updateDrmSessionV23(); updateDrmSessionV23();
} catch (ExoPlaybackException e) { } catch (ExoPlaybackException e) {
@ -1215,7 +1216,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
long codecInitializedTimestamp; long codecInitializedTimestamp;
String codecName = codecInfo.name; String codecName = codecInfo.name;
float codecOperatingRate = float codecOperatingRate =
Util.SDK_INT < 23 SDK_INT < 23
? CODEC_OPERATING_RATE_UNSET ? CODEC_OPERATING_RATE_UNSET
: getCodecOperatingRateV23(targetPlaybackSpeed, inputFormat, getStreamFormats()); : getCodecOperatingRateV23(targetPlaybackSpeed, inputFormat, getStreamFormats());
if (codecOperatingRate <= assumedMinimumCodecOperatingRate) { if (codecOperatingRate <= assumedMinimumCodecOperatingRate) {
@ -1224,7 +1225,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codecInitializingTimestamp = getClock().elapsedRealtime(); codecInitializingTimestamp = getClock().elapsedRealtime();
MediaCodecAdapter.Configuration configuration = MediaCodecAdapter.Configuration configuration =
getMediaCodecConfiguration(codecInfo, inputFormat, crypto, codecOperatingRate); getMediaCodecConfiguration(codecInfo, inputFormat, crypto, codecOperatingRate);
if (Util.SDK_INT >= 31) { if (SDK_INT >= 31) {
Api31.setLogSessionIdToMediaCodecFormat(configuration, getPlayerId()); Api31.setLogSessionIdToMediaCodecFormat(configuration, getPlayerId());
} }
try { try {
@ -1610,7 +1611,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
DISCARD_REASON_DRM_SESSION_CHANGED); DISCARD_REASON_DRM_SESSION_CHANGED);
} }
boolean drainAndUpdateCodecDrmSession = sourceDrmSession != codecDrmSession; boolean drainAndUpdateCodecDrmSession = sourceDrmSession != codecDrmSession;
Assertions.checkState(!drainAndUpdateCodecDrmSession || Util.SDK_INT >= 23); Assertions.checkState(!drainAndUpdateCodecDrmSession || SDK_INT >= 23);
DecoderReuseEvaluation evaluation = canReuseCodec(codecInfo, oldFormat, newFormat); DecoderReuseEvaluation evaluation = canReuseCodec(codecInfo, oldFormat, newFormat);
@DecoderDiscardReasons int overridingDiscardReasons = 0; @DecoderDiscardReasons int overridingDiscardReasons = 0;
@ -1899,7 +1900,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
* @return False if codec release and re-initialization was triggered. True in all other cases. * @return False if codec release and re-initialization was triggered. True in all other cases.
*/ */
private boolean updateCodecOperatingRate(@Nullable Format format) throws ExoPlaybackException { private boolean updateCodecOperatingRate(@Nullable Format format) throws ExoPlaybackException {
if (Util.SDK_INT < 23) { if (SDK_INT < 23) {
return true; return true;
} }
@ -2323,7 +2324,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
return true; return true;
} }
if (Util.SDK_INT < 23) { if (SDK_INT < 23) {
// MediaCrypto.setMediaDrmSession is only available from API level 23, so re-initialization is // MediaCrypto.setMediaDrmSession is only available from API level 23, so re-initialization is
// required to switch to newSession on older API levels. // required to switch to newSession on older API levels.
return true; return true;
@ -2572,14 +2573,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
* @return The mode specifying when the adaptation workaround should be enabled. * @return The mode specifying when the adaptation workaround should be enabled.
*/ */
private @AdaptationWorkaroundMode int codecAdaptationWorkaroundMode(String name) { private @AdaptationWorkaroundMode int codecAdaptationWorkaroundMode(String name) {
if (Util.SDK_INT <= 25 if (SDK_INT <= 25
&& "OMX.Exynos.avc.dec.secure".equals(name) && "OMX.Exynos.avc.dec.secure".equals(name)
&& (Build.MODEL.startsWith("SM-T585") && (Build.MODEL.startsWith("SM-T585")
|| Build.MODEL.startsWith("SM-A510") || Build.MODEL.startsWith("SM-A510")
|| Build.MODEL.startsWith("SM-A520") || Build.MODEL.startsWith("SM-A520")
|| Build.MODEL.startsWith("SM-J700"))) { || Build.MODEL.startsWith("SM-J700"))) {
return ADAPTATION_WORKAROUND_MODE_ALWAYS; return ADAPTATION_WORKAROUND_MODE_ALWAYS;
} else if (Util.SDK_INT < 24 } else if (SDK_INT < 24
&& ("OMX.Nvidia.h264.decode".equals(name) || "OMX.Nvidia.h264.decode.secure".equals(name)) && ("OMX.Nvidia.h264.decode".equals(name) || "OMX.Nvidia.h264.decode.secure".equals(name))
&& ("flounder".equals(Build.DEVICE) && ("flounder".equals(Build.DEVICE)
|| "flounder_lte".equals(Build.DEVICE) || "flounder_lte".equals(Build.DEVICE)
@ -2605,7 +2606,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
* {@link MediaFormat}. False otherwise. * {@link MediaFormat}. False otherwise.
*/ */
private static boolean codecNeedsSosFlushWorkaround(String name) { private static boolean codecNeedsSosFlushWorkaround(String name) {
return Util.SDK_INT == 29 && "c2.android.aac.decoder".equals(name); return SDK_INT == 29 && "c2.android.aac.decoder".equals(name);
} }
/** /**
@ -2622,8 +2623,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
*/ */
private static boolean codecNeedsEosPropagationWorkaround(MediaCodecInfo codecInfo) { private static boolean codecNeedsEosPropagationWorkaround(MediaCodecInfo codecInfo) {
String name = codecInfo.name; String name = codecInfo.name;
return (Util.SDK_INT <= 25 && "OMX.rk.video_decoder.avc".equals(name)) return (SDK_INT <= 25 && "OMX.rk.video_decoder.avc".equals(name))
|| (Util.SDK_INT <= 29 || (SDK_INT <= 29
&& ("OMX.broadcom.video_decoder.tunnel".equals(name) && ("OMX.broadcom.video_decoder.tunnel".equals(name)
|| "OMX.broadcom.video_decoder.tunnel.secure".equals(name) || "OMX.broadcom.video_decoder.tunnel.secure".equals(name)
|| "OMX.bcm.vdec.avc.tunnel".equals(name) || "OMX.bcm.vdec.avc.tunnel".equals(name)
@ -2647,7 +2648,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
* buffer with {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM} set. False otherwise. * buffer with {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM} set. False otherwise.
*/ */
private static boolean codecNeedsEosFlushWorkaround(String name) { private static boolean codecNeedsEosFlushWorkaround(String name) {
return Util.SDK_INT <= 23 && "OMX.google.vorbis.decoder".equals(name); return SDK_INT <= 23 && "OMX.google.vorbis.decoder".equals(name);
} }
/** /**
@ -2662,7 +2663,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
* @return True if the decoder may throw an exception after receiving an end-of-stream buffer. * @return True if the decoder may throw an exception after receiving an end-of-stream buffer.
*/ */
private static boolean codecNeedsEosOutputExceptionWorkaround(String name) { private static boolean codecNeedsEosOutputExceptionWorkaround(String name) {
return Util.SDK_INT == 21 && "OMX.google.aac.decoder".equals(name); return SDK_INT == 21 && "OMX.google.aac.decoder".equals(name);
} }
private static final class OutputStreamInfo { private static final class OutputStreamInfo {

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.mediacodec; package androidx.media3.exoplayer.mediacodec;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.CodecSpecificDataUtil.getHevcProfileAndLevel; import static androidx.media3.common.util.CodecSpecificDataUtil.getHevcProfileAndLevel;
import static java.lang.Math.max; import static java.lang.Math.max;
@ -158,7 +159,7 @@ public final class MediaCodecUtil {
MediaCodecListCompat mediaCodecList = MediaCodecListCompat mediaCodecList =
new MediaCodecListCompatV21(secure, tunneling, specialCodec); new MediaCodecListCompatV21(secure, tunneling, specialCodec);
ArrayList<MediaCodecInfo> decoderInfos = getDecoderInfosInternal(key, mediaCodecList); ArrayList<MediaCodecInfo> decoderInfos = getDecoderInfosInternal(key, mediaCodecList);
if (secure && decoderInfos.isEmpty() && Util.SDK_INT <= 23) { if (secure && decoderInfos.isEmpty() && SDK_INT <= 23) {
// Some devices don't list secure decoders on API level 21 [Internal: b/18678462]. Try the // Some devices don't list secure decoders on API level 21 [Internal: b/18678462]. Try the
// legacy path. We also try this path on API levels 22 and 23 as a defensive measure. // legacy path. We also try this path on API levels 22 and 23 as a defensive measure.
mediaCodecList = new MediaCodecListCompatV16(); mediaCodecList = new MediaCodecListCompatV16();
@ -490,7 +491,7 @@ public final class MediaCodecUtil {
return decoderInfos; return decoderInfos;
} }
} catch (Exception e) { } catch (Exception e) {
if (Util.SDK_INT <= 23 && !decoderInfos.isEmpty()) { if (SDK_INT <= 23 && !decoderInfos.isEmpty()) {
// Suppress error querying secondary codec capabilities up to API level 23. // Suppress error querying secondary codec capabilities up to API level 23.
Log.e(TAG, "Skipping codec " + name + " (failed to query capabilities)"); Log.e(TAG, "Skipping codec " + name + " (failed to query capabilities)");
} else { } else {
@ -574,7 +575,7 @@ public final class MediaCodecUtil {
} }
// Work around https://github.com/google/ExoPlayer/issues/3249. // Work around https://github.com/google/ExoPlayer/issues/3249.
if (Util.SDK_INT < 24 if (SDK_INT < 24
&& ("OMX.SEC.aac.dec".equals(name) || "OMX.Exynos.AAC.Decoder".equals(name)) && ("OMX.SEC.aac.dec".equals(name) || "OMX.Exynos.AAC.Decoder".equals(name))
&& "samsung".equals(Build.MANUFACTURER) && "samsung".equals(Build.MANUFACTURER)
&& (Build.DEVICE.startsWith("zeroflte") // Galaxy S6 && (Build.DEVICE.startsWith("zeroflte") // Galaxy S6
@ -589,7 +590,7 @@ public final class MediaCodecUtil {
} }
// MTK AC3 decoder doesn't support decoding JOC streams in 2-D. See [Internal: b/69400041]. // MTK AC3 decoder doesn't support decoding JOC streams in 2-D. See [Internal: b/69400041].
if (Util.SDK_INT <= 23 if (SDK_INT <= 23
&& MimeTypes.AUDIO_E_AC3_JOC.equals(mimeType) && MimeTypes.AUDIO_E_AC3_JOC.equals(mimeType)
&& "OMX.MTK.AUDIO.DECODER.DSPAC3".equals(name)) { && "OMX.MTK.AUDIO.DECODER.DSPAC3".equals(name)) {
return false; return false;
@ -607,7 +608,7 @@ public final class MediaCodecUtil {
*/ */
private static void applyWorkarounds(String mimeType, List<MediaCodecInfo> decoderInfos) { private static void applyWorkarounds(String mimeType, List<MediaCodecInfo> decoderInfos) {
if (MimeTypes.AUDIO_RAW.equals(mimeType)) { if (MimeTypes.AUDIO_RAW.equals(mimeType)) {
if (Util.SDK_INT < 26 if (SDK_INT < 26
&& Build.DEVICE.equals("R9") && Build.DEVICE.equals("R9")
&& decoderInfos.size() == 1 && decoderInfos.size() == 1
&& decoderInfos.get(0).name.equals("OMX.MTK.AUDIO.DECODER.RAW")) { && decoderInfos.get(0).name.equals("OMX.MTK.AUDIO.DECODER.RAW")) {
@ -634,7 +635,7 @@ public final class MediaCodecUtil {
// Prefer generic decoders over ones provided by the device. // Prefer generic decoders over ones provided by the device.
return 1; return 1;
} }
if (Util.SDK_INT < 26 && name.equals("OMX.MTK.AUDIO.DECODER.RAW")) { if (SDK_INT < 26 && name.equals("OMX.MTK.AUDIO.DECODER.RAW")) {
// This decoder may modify the audio, so any other compatible decoders take // This decoder may modify the audio, so any other compatible decoders take
// precedence. See [Internal: b/62337687]. // precedence. See [Internal: b/62337687].
return -1; return -1;
@ -643,7 +644,7 @@ public final class MediaCodecUtil {
}); });
} }
if (Util.SDK_INT < 32 && decoderInfos.size() > 1) { if (SDK_INT < 32 && decoderInfos.size() > 1) {
String firstCodecName = decoderInfos.get(0).name; String firstCodecName = decoderInfos.get(0).name;
// Prefer anything other than OMX.qti.audio.decoder.flac on older devices. See [Internal // Prefer anything other than OMX.qti.audio.decoder.flac on older devices. See [Internal
// ref: b/199124812]. // ref: b/199124812].
@ -654,7 +655,7 @@ public final class MediaCodecUtil {
} }
private static boolean isAlias(android.media.MediaCodecInfo info) { private static boolean isAlias(android.media.MediaCodecInfo info) {
return Util.SDK_INT >= 29 && isAliasV29(info); return SDK_INT >= 29 && isAliasV29(info);
} }
@RequiresApi(29) @RequiresApi(29)
@ -668,7 +669,7 @@ public final class MediaCodecUtil {
*/ */
private static boolean isHardwareAccelerated( private static boolean isHardwareAccelerated(
android.media.MediaCodecInfo codecInfo, String mimeType) { android.media.MediaCodecInfo codecInfo, String mimeType) {
if (Util.SDK_INT >= 29) { if (SDK_INT >= 29) {
return isHardwareAcceleratedV29(codecInfo); return isHardwareAcceleratedV29(codecInfo);
} }
// codecInfo.isHardwareAccelerated() != codecInfo.isSoftwareOnly() is not necessarily true. // codecInfo.isHardwareAccelerated() != codecInfo.isSoftwareOnly() is not necessarily true.
@ -686,7 +687,7 @@ public final class MediaCodecUtil {
* best-effort approximation for lower levels. * best-effort approximation for lower levels.
*/ */
private static boolean isSoftwareOnly(android.media.MediaCodecInfo codecInfo, String mimeType) { private static boolean isSoftwareOnly(android.media.MediaCodecInfo codecInfo, String mimeType) {
if (Util.SDK_INT >= 29) { if (SDK_INT >= 29) {
return isSoftwareOnlyV29(codecInfo); return isSoftwareOnlyV29(codecInfo);
} }
if (MimeTypes.isAudio(mimeType)) { if (MimeTypes.isAudio(mimeType)) {
@ -717,7 +718,7 @@ public final class MediaCodecUtil {
* best-effort approximation for lower levels. * best-effort approximation for lower levels.
*/ */
private static boolean isVendor(android.media.MediaCodecInfo codecInfo) { private static boolean isVendor(android.media.MediaCodecInfo codecInfo) {
if (Util.SDK_INT >= 29) { if (SDK_INT >= 29) {
return isVendorV29(codecInfo); return isVendorV29(codecInfo);
} }
String codecName = Ascii.toLowerCase(codecInfo.getName()); String codecName = Ascii.toLowerCase(codecInfo.getName());

View File

@ -16,6 +16,7 @@
package androidx.media3.exoplayer.mediacodec; package androidx.media3.exoplayer.mediacodec;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
@ -30,7 +31,6 @@ import androidx.annotation.RequiresApi;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.util.TraceUtil; import androidx.media3.common.util.TraceUtil;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.decoder.CryptoInfo; import androidx.media3.decoder.CryptoInfo;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -54,7 +54,7 @@ public final class SynchronousMediaCodecAdapter implements MediaCodecAdapter {
int flags = 0; int flags = 0;
if (configuration.surface == null if (configuration.surface == null
&& configuration.codecInfo.detachedSurfaceSupported && configuration.codecInfo.detachedSurfaceSupported
&& Util.SDK_INT >= 35) { && SDK_INT >= 35) {
flags |= MediaCodec.CONFIGURE_FLAG_DETACHED_SURFACE; flags |= MediaCodec.CONFIGURE_FLAG_DETACHED_SURFACE;
} }
codec.configure( codec.configure(
@ -90,7 +90,7 @@ public final class SynchronousMediaCodecAdapter implements MediaCodecAdapter {
MediaCodec mediaCodec, @Nullable LoudnessCodecController loudnessCodecController) { MediaCodec mediaCodec, @Nullable LoudnessCodecController loudnessCodecController) {
this.codec = mediaCodec; this.codec = mediaCodec;
this.loudnessCodecController = loudnessCodecController; this.loudnessCodecController = loudnessCodecController;
if (Util.SDK_INT >= 35 && loudnessCodecController != null) { if (SDK_INT >= 35 && loudnessCodecController != null) {
loudnessCodecController.addMediaCodec(codec); loudnessCodecController.addMediaCodec(codec);
} }
} }
@ -163,7 +163,7 @@ public final class SynchronousMediaCodecAdapter implements MediaCodecAdapter {
@Override @Override
public void release() { public void release() {
try { try {
if (Util.SDK_INT >= 30 && Util.SDK_INT < 33) { if (SDK_INT >= 30 && SDK_INT < 33) {
// Stopping the codec before releasing it works around a bug on APIs 30, 31 and 32 where // Stopping the codec before releasing it works around a bug on APIs 30, 31 and 32 where
// MediaCodec.release() returns too early before fully detaching a Surface, and a // MediaCodec.release() returns too early before fully detaching a Surface, and a
// subsequent MediaCodec.configure() call using the same Surface then fails. See // subsequent MediaCodec.configure() call using the same Surface then fails. See
@ -171,7 +171,7 @@ public final class SynchronousMediaCodecAdapter implements MediaCodecAdapter {
codec.stop(); codec.stop();
} }
} finally { } finally {
if (Util.SDK_INT >= 35 && loudnessCodecController != null) { if (SDK_INT >= 35 && loudnessCodecController != null) {
loudnessCodecController.removeMediaCodec(codec); loudnessCodecController.removeMediaCodec(codec);
} }
codec.release(); codec.release();

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.offline; package androidx.media3.exoplayer.offline;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.core.app.NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE; import static androidx.core.app.NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
@ -28,7 +29,6 @@ import androidx.annotation.StringRes;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.R; import androidx.media3.exoplayer.R;
import androidx.media3.exoplayer.scheduler.Requirements; import androidx.media3.exoplayer.scheduler.Requirements;
import java.util.List; import java.util.List;
@ -227,7 +227,7 @@ public final class DownloadNotificationHelper {
notificationBuilder.setProgress(maxProgress, currentProgress, indeterminateProgress); notificationBuilder.setProgress(maxProgress, currentProgress, indeterminateProgress);
notificationBuilder.setOngoing(ongoing); notificationBuilder.setOngoing(ongoing);
notificationBuilder.setShowWhen(showWhen); notificationBuilder.setShowWhen(showWhen);
if (Util.SDK_INT >= 31) { if (SDK_INT >= 31) {
Api31.setForegroundServiceBehavior(notificationBuilder); Api31.setForegroundServiceBehavior(notificationBuilder);
} }
return notificationBuilder.build(); return notificationBuilder.build();

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.offline; package androidx.media3.exoplayer.offline;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.exoplayer.offline.Download.STOP_REASON_NONE; import static androidx.media3.exoplayer.offline.Download.STOP_REASON_NONE;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
@ -595,7 +596,7 @@ public abstract class DownloadService extends Service {
if (downloadManagerHelper == null) { if (downloadManagerHelper == null) {
boolean foregroundAllowed = foregroundNotificationUpdater != null; boolean foregroundAllowed = foregroundNotificationUpdater != null;
// See https://developer.android.com/about/versions/12/foreground-services. // See https://developer.android.com/about/versions/12/foreground-services.
boolean canStartForegroundServiceFromBackground = Util.SDK_INT < 31; boolean canStartForegroundServiceFromBackground = SDK_INT < 31;
@Nullable @Nullable
Scheduler scheduler = Scheduler scheduler =
foregroundAllowed && canStartForegroundServiceFromBackground ? getScheduler() : null; foregroundAllowed && canStartForegroundServiceFromBackground ? getScheduler() : null;
@ -683,7 +684,7 @@ public abstract class DownloadService extends Service {
break; break;
} }
if (Util.SDK_INT >= 26 && startedInForeground && foregroundNotificationUpdater != null) { if (SDK_INT >= 26 && startedInForeground && foregroundNotificationUpdater != null) {
// From API level 26, services started in the foreground are required to show a notification. // From API level 26, services started in the foreground are required to show a notification.
foregroundNotificationUpdater.showNotificationIfNotAlready(); foregroundNotificationUpdater.showNotificationIfNotAlready();
} }
@ -844,7 +845,7 @@ public abstract class DownloadService extends Service {
// Stop the service, either because the DownloadManager is not waiting for requirements to be // Stop the service, either because the DownloadManager is not waiting for requirements to be
// met, or because we've scheduled the service to be restarted when they are. // met, or because we've scheduled the service to be restarted when they are.
if (Util.SDK_INT < 28 && taskRemoved) { // See [Internal: b/74248644]. if (SDK_INT < 28 && taskRemoved) { // See [Internal: b/74248644].
stopSelf(); stopSelf();
isStopped = true; isStopped = true;
} else { } else {

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.scheduler; package androidx.media3.exoplayer.scheduler;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import android.app.job.JobInfo; import android.app.job.JobInfo;
@ -55,7 +56,7 @@ public final class PlatformScheduler implements Scheduler {
| Requirements.NETWORK_UNMETERED | Requirements.NETWORK_UNMETERED
| Requirements.DEVICE_IDLE | Requirements.DEVICE_IDLE
| Requirements.DEVICE_CHARGING | Requirements.DEVICE_CHARGING
| (Util.SDK_INT >= 26 ? Requirements.DEVICE_STORAGE_NOT_LOW : 0); | (SDK_INT >= 26 ? Requirements.DEVICE_STORAGE_NOT_LOW : 0);
private final int jobId; private final int jobId;
private final ComponentName jobServiceComponentName; private final ComponentName jobServiceComponentName;
@ -120,7 +121,7 @@ public final class PlatformScheduler implements Scheduler {
} }
builder.setRequiresDeviceIdle(requirements.isIdleRequired()); builder.setRequiresDeviceIdle(requirements.isIdleRequired());
builder.setRequiresCharging(requirements.isChargingRequired()); builder.setRequiresCharging(requirements.isChargingRequired());
if (Util.SDK_INT >= 26 && requirements.isStorageNotLowRequired()) { if (SDK_INT >= 26 && requirements.isStorageNotLowRequired()) {
builder.setRequiresStorageNotLow(true); builder.setRequiresStorageNotLow(true);
} }
builder.setPersisted(true); builder.setPersisted(true);

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.scheduler; package androidx.media3.exoplayer.scheduler;
import static android.os.Build.VERSION.SDK_INT;
import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE; import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.METHOD;
@ -36,7 +37,6 @@ import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -202,7 +202,7 @@ public final class Requirements implements Parcelable {
private boolean isDeviceIdle(Context context) { private boolean isDeviceIdle(Context context) {
PowerManager powerManager = PowerManager powerManager =
(PowerManager) Assertions.checkNotNull(context.getSystemService(Context.POWER_SERVICE)); (PowerManager) Assertions.checkNotNull(context.getSystemService(Context.POWER_SERVICE));
return Util.SDK_INT >= 23 ? powerManager.isDeviceIdleMode() : !powerManager.isInteractive(); return SDK_INT >= 23 ? powerManager.isDeviceIdleMode() : !powerManager.isInteractive();
} }
private boolean isStorageNotLow(Context context) { private boolean isStorageNotLow(Context context) {
@ -216,7 +216,7 @@ public final class Requirements implements Parcelable {
// RequirementsWatcher only fires an event to re-check the requirements when NetworkCapabilities // RequirementsWatcher only fires an event to re-check the requirements when NetworkCapabilities
// change from API level 24. We assume that network capability is validated for API level 23 to // change from API level 24. We assume that network capability is validated for API level 23 to
// keep in sync. // keep in sync.
if (Util.SDK_INT < 24) { if (SDK_INT < 24) {
return true; return true;
} }

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.scheduler; package androidx.media3.exoplayer.scheduler;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
@ -88,7 +89,7 @@ public final class RequirementsWatcher {
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
if (requirements.isNetworkRequired()) { if (requirements.isNetworkRequired()) {
if (Util.SDK_INT >= 24) { if (SDK_INT >= 24) {
registerNetworkCallbackV24(); registerNetworkCallbackV24();
} else { } else {
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
@ -99,7 +100,7 @@ public final class RequirementsWatcher {
filter.addAction(Intent.ACTION_POWER_DISCONNECTED); filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
} }
if (requirements.isIdleRequired()) { if (requirements.isIdleRequired()) {
if (Util.SDK_INT >= 23) { if (SDK_INT >= 23) {
filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
} else { } else {
filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_ON);
@ -119,7 +120,7 @@ public final class RequirementsWatcher {
public void stop() { public void stop() {
context.unregisterReceiver(checkNotNull(receiver)); context.unregisterReceiver(checkNotNull(receiver));
receiver = null; receiver = null;
if (Util.SDK_INT >= 24 && networkCallback != null) { if (SDK_INT >= 24 && networkCallback != null) {
unregisterNetworkCallbackV24(); unregisterNetworkCallbackV24();
} }
} }

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.source; package androidx.media3.exoplayer.source;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_EAGERLY_EXPOSE_TRACK_TYPE; import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_EAGERLY_EXPOSE_TRACK_TYPE;
import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_INCLUDE_SUPPLEMENTAL_DATA; import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_INCLUDE_SUPPLEMENTAL_DATA;
import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_IN_BAND_CRYPTO_INFO; import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_IN_BAND_CRYPTO_INFO;
@ -28,7 +29,6 @@ import androidx.annotation.RequiresApi;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.DataReader; import androidx.media3.common.DataReader;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.analytics.PlayerId; import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.source.mediaparser.InputReaderAdapterV30; import androidx.media3.exoplayer.source.mediaparser.InputReaderAdapterV30;
import androidx.media3.exoplayer.source.mediaparser.MediaParserUtil; import androidx.media3.exoplayer.source.mediaparser.MediaParserUtil;
@ -107,7 +107,7 @@ public final class MediaParserExtractorAdapter implements ProgressiveMediaExtrac
mediaParser.setParameter(parameter.getKey(), parameter.getValue()); mediaParser.setParameter(parameter.getKey(), parameter.getValue());
} }
parserName = MediaParser.PARSER_NAME_UNKNOWN; parserName = MediaParser.PARSER_NAME_UNKNOWN;
if (Util.SDK_INT >= 31) { if (SDK_INT >= 31) {
MediaParserUtil.setLogSessionIdOnMediaParser(mediaParser, playerId); MediaParserUtil.setLogSessionIdOnMediaParser(mediaParser, playerId);
} }
} }

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.source.chunk; package androidx.media3.exoplayer.source.chunk;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_EAGERLY_EXPOSE_TRACK_TYPE; import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_EAGERLY_EXPOSE_TRACK_TYPE;
import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_EXPOSE_CAPTION_FORMATS; import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_EXPOSE_CAPTION_FORMATS;
@ -34,7 +35,6 @@ import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.analytics.PlayerId; import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.source.mediaparser.InputReaderAdapterV30; import androidx.media3.exoplayer.source.mediaparser.InputReaderAdapterV30;
import androidx.media3.exoplayer.source.mediaparser.MediaParserUtil; import androidx.media3.exoplayer.source.mediaparser.MediaParserUtil;
@ -196,7 +196,7 @@ public final class MediaParserChunkExtractor implements ChunkExtractor {
MediaParserUtil.toCaptionsMediaFormat(closedCaptionFormats.get(i))); MediaParserUtil.toCaptionsMediaFormat(closedCaptionFormats.get(i)));
} }
mediaParser.setParameter(PARAMETER_EXPOSE_CAPTION_FORMATS, closedCaptionMediaFormats); mediaParser.setParameter(PARAMETER_EXPOSE_CAPTION_FORMATS, closedCaptionMediaFormats);
if (Util.SDK_INT >= 31) { if (SDK_INT >= 31) {
MediaParserUtil.setLogSessionIdOnMediaParser(mediaParser, playerId); MediaParserUtil.setLogSessionIdOnMediaParser(mediaParser, playerId);
} }
outputConsumerAdapter.setMuxedCaptionFormats(closedCaptionFormats); outputConsumerAdapter.setMuxedCaptionFormats(closedCaptionFormats);

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.trackselection; package androidx.media3.exoplayer.trackselection;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.TrackSelectionParameters.AudioOffloadPreferences.AUDIO_OFFLOAD_MODE_DISABLED; import static androidx.media3.common.TrackSelectionParameters.AudioOffloadPreferences.AUDIO_OFFLOAD_MODE_DISABLED;
import static androidx.media3.common.TrackSelectionParameters.AudioOffloadPreferences.AUDIO_OFFLOAD_MODE_REQUIRED; import static androidx.media3.common.TrackSelectionParameters.AudioOffloadPreferences.AUDIO_OFFLOAD_MODE_REQUIRED;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
@ -2482,7 +2483,7 @@ public class DefaultTrackSelector extends MappingTrackSelector
@Override @Override
public void release() { public void release() {
if (Util.SDK_INT >= 32 && spatializer != null) { if (SDK_INT >= 32 && spatializer != null) {
spatializer.release(); spatializer.release();
} }
super.release(); super.release();
@ -2592,7 +2593,7 @@ public class DefaultTrackSelector extends MappingTrackSelector
parameters = this.parameters; parameters = this.parameters;
} }
if (parameters.constrainAudioChannelCountToDeviceCapabilities if (parameters.constrainAudioChannelCountToDeviceCapabilities
&& Util.SDK_INT >= 32 && SDK_INT >= 32
&& spatializer == null) { && spatializer == null) {
spatializer = new SpatializerWrapperV32(context, /* defaultTrackSelector= */ this); spatializer = new SpatializerWrapperV32(context, /* defaultTrackSelector= */ this);
} }
@ -2868,10 +2869,8 @@ public class DefaultTrackSelector extends MappingTrackSelector
return !parameters.constrainAudioChannelCountToDeviceCapabilities return !parameters.constrainAudioChannelCountToDeviceCapabilities
|| (format.channelCount == Format.NO_VALUE || format.channelCount <= 2) || (format.channelCount == Format.NO_VALUE || format.channelCount <= 2)
|| (isDolbyAudio(format) || (isDolbyAudio(format)
&& (Util.SDK_INT < 32 && (SDK_INT < 32 || spatializer == null || !spatializer.isSpatializationSupported()))
|| spatializer == null || (SDK_INT >= 32
|| !spatializer.isSpatializationSupported()))
|| (Util.SDK_INT >= 32
&& spatializer != null && spatializer != null
&& spatializer.isSpatializationSupported() && spatializer.isSpatializationSupported()
&& spatializer.isAvailable() && spatializer.isAvailable()
@ -3065,7 +3064,7 @@ public class DefaultTrackSelector extends MappingTrackSelector
synchronized (lock) { synchronized (lock) {
shouldInvalidate = shouldInvalidate =
parameters.constrainAudioChannelCountToDeviceCapabilities parameters.constrainAudioChannelCountToDeviceCapabilities
&& Util.SDK_INT >= 32 && SDK_INT >= 32
&& spatializer != null && spatializer != null
&& spatializer.isSpatializationSupported(); && spatializer.isSpatializationSupported();
} }

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.video; package androidx.media3.exoplayer.video;
import static android.os.Build.VERSION.SDK_INT;
import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
@ -764,7 +765,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@DecoderSupport @DecoderSupport
int decoderSupport = isPreferredDecoder ? DECODER_SUPPORT_PRIMARY : DECODER_SUPPORT_FALLBACK; int decoderSupport = isPreferredDecoder ? DECODER_SUPPORT_PRIMARY : DECODER_SUPPORT_FALLBACK;
if (Util.SDK_INT >= 26 if (SDK_INT >= 26
&& MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType) && MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType)
&& !Api26.doesDisplaySupportDolbyVision(context)) { && !Api26.doesDisplaySupportDolbyVision(context)) {
decoderSupport = DECODER_SUPPORT_FALLBACK_MIMETYPE; decoderSupport = DECODER_SUPPORT_FALLBACK_MIMETYPE;
@ -835,7 +836,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
if (format.sampleMimeType == null) { if (format.sampleMimeType == null) {
return ImmutableList.of(); return ImmutableList.of();
} }
if (Util.SDK_INT >= 26 if (SDK_INT >= 26
&& MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType) && MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType)
&& !Api26.doesDisplaySupportDolbyVision(context)) { && !Api26.doesDisplaySupportDolbyVision(context)) {
List<MediaCodecInfo> alternativeDecoderInfos = List<MediaCodecInfo> alternativeDecoderInfos =
@ -982,6 +983,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
Context context, VideoFrameReleaseControl videoFrameReleaseControl) { Context context, VideoFrameReleaseControl videoFrameReleaseControl) {
// TODO: b/391109644 - Add a more explicit API to enable replaying. // TODO: b/391109644 - Add a more explicit API to enable replaying.
return new PlaybackVideoGraphWrapper.Builder(context, videoFrameReleaseControl) return new PlaybackVideoGraphWrapper.Builder(context, videoFrameReleaseControl)
.setEnablePlaylistMode(true)
.setClock(getClock()) .setClock(getClock())
.build(); .build();
} }
@ -1214,7 +1216,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
if (codec != null && videoSink == null) { if (codec != null && videoSink == null) {
MediaCodecInfo codecInfo = checkNotNull(getCodecInfo()); MediaCodecInfo codecInfo = checkNotNull(getCodecInfo());
boolean canUpdateSurface = hasSurfaceForCodec(codecInfo); boolean canUpdateSurface = hasSurfaceForCodec(codecInfo);
if (Util.SDK_INT >= 23 && canUpdateSurface && !codecNeedsSetOutputSurfaceWorkaround) { if (SDK_INT >= 23 && canUpdateSurface && !codecNeedsSetOutputSurfaceWorkaround) {
setOutputSurface(codec, getSurfaceForCodec(codecInfo)); setOutputSurface(codec, getSurfaceForCodec(codecInfo));
} else { } else {
releaseCodec(); releaseCodec();
@ -1259,7 +1261,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Override @Override
protected boolean getCodecNeedsEosPropagation() { protected boolean getCodecNeedsEosPropagation() {
// Since API 23, onFrameRenderedListener allows for detection of the renderer EOS. // Since API 23, onFrameRenderedListener allows for detection of the renderer EOS.
return tunneling && Util.SDK_INT < 23; return tunneling && SDK_INT < 23;
} }
@Override @Override
@ -1525,7 +1527,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
if (!tunneling) { if (!tunneling) {
buffersInCodecCount++; buffersInCodecCount++;
} }
if (Util.SDK_INT < 23 && tunneling) { if (SDK_INT < 23 && tunneling) {
// In tunneled mode before API 23 we don't have a way to know when the buffer is output, so // In tunneled mode before API 23 we don't have a way to know when the buffer is output, so
// treat it as if it were output immediately. // treat it as if it were output immediately.
onProcessedTunneledBuffer(buffer.timeUs); onProcessedTunneledBuffer(buffer.timeUs);
@ -1534,7 +1536,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Override @Override
protected int getCodecBufferFlags(DecoderInputBuffer buffer) { protected int getCodecBufferFlags(DecoderInputBuffer buffer) {
if (Util.SDK_INT >= 34 if (SDK_INT >= 34
&& (enableMediaCodecBufferDecodeOnlyFlag || tunneling) && (enableMediaCodecBufferDecodeOnlyFlag || tunneling)
&& isBufferBeforeStartTime(buffer)) { && isBufferBeforeStartTime(buffer)) {
// The buffer likely needs to be dropped because its timestamp is less than the start time. // The buffer likely needs to be dropped because its timestamp is less than the start time.
@ -2146,11 +2148,11 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
} }
protected boolean shouldUseDetachedSurface(MediaCodecInfo codecInfo) { protected boolean shouldUseDetachedSurface(MediaCodecInfo codecInfo) {
return Util.SDK_INT >= 35 && codecInfo.detachedSurfaceSupported; return SDK_INT >= 35 && codecInfo.detachedSurfaceSupported;
} }
protected boolean shouldUsePlaceholderSurface(MediaCodecInfo codecInfo) { protected boolean shouldUsePlaceholderSurface(MediaCodecInfo codecInfo) {
return Util.SDK_INT >= 23 return SDK_INT >= 23
&& !tunneling && !tunneling
&& !codecNeedsSetOutputSurfaceWorkaround(codecInfo.name) && !codecNeedsSetOutputSurfaceWorkaround(codecInfo.name)
&& (!codecInfo.secure || PlaceholderSurface.isSecureSupported(context)); && (!codecInfo.secure || PlaceholderSurface.isSecureSupported(context));
@ -2164,7 +2166,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
} }
private void maybeSetupTunnelingForFirstFrame() { private void maybeSetupTunnelingForFirstFrame() {
if (!tunneling || Util.SDK_INT < 23) { if (!tunneling || SDK_INT < 23) {
// The first frame notification for tunneling is triggered by onQueueInputBuffer prior to API // The first frame notification for tunneling is triggered by onQueueInputBuffer prior to API
// level 23 and no setup is needed here. // level 23 and no setup is needed here.
return; return;
@ -2175,7 +2177,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
return; return;
} }
tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(codec); tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(codec);
if (Util.SDK_INT >= 33) { if (SDK_INT >= 33) {
// This should be the default anyway according to the API contract, but some devices are known // This should be the default anyway according to the API contract, but some devices are known
// to not adhere to this contract and need to get the parameter explicitly. See // to not adhere to this contract and need to get the parameter explicitly. See
// https://github.com/androidx/media/issues/1169. // https://github.com/androidx/media/issues/1169.
@ -2191,7 +2193,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
// If codec is null, then the importance will be set when initializing the codec. // If codec is null, then the importance will be set when initializing the codec.
return; return;
} }
if (Util.SDK_INT >= 35) { if (SDK_INT >= 35) {
Bundle codecParameters = new Bundle(); Bundle codecParameters = new Bundle();
codecParameters.putInt(MediaFormat.KEY_IMPORTANCE, max(0, -rendererPriority)); codecParameters.putInt(MediaFormat.KEY_IMPORTANCE, max(0, -rendererPriority));
codec.setParameters(codecParameters); codec.setParameters(codecParameters);
@ -2257,9 +2259,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
} }
private void setOutputSurface(MediaCodecAdapter codec, @Nullable Surface surface) { private void setOutputSurface(MediaCodecAdapter codec, @Nullable Surface surface) {
if (Util.SDK_INT >= 23 && surface != null) { if (SDK_INT >= 23 && surface != null) {
setOutputSurfaceV23(codec, surface); setOutputSurfaceV23(codec, surface);
} else if (Util.SDK_INT >= 35) { } else if (SDK_INT >= 35) {
detachOutputSurfaceV35(codec); detachOutputSurfaceV35(codec);
} else { } else {
throw new IllegalStateException(); throw new IllegalStateException();
@ -2323,7 +2325,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
MediaFormatUtil.maybeSetInteger( MediaFormatUtil.maybeSetInteger(
mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE, codecMaxValues.inputSize); mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE, codecMaxValues.inputSize);
// Set codec configuration values. // Set codec configuration values.
if (Util.SDK_INT >= 23) { if (SDK_INT >= 23) {
mediaFormat.setInteger(MediaFormat.KEY_PRIORITY, 0 /* realtime priority */); mediaFormat.setInteger(MediaFormat.KEY_PRIORITY, 0 /* realtime priority */);
if (codecOperatingRate != CODEC_OPERATING_RATE_UNSET) { if (codecOperatingRate != CODEC_OPERATING_RATE_UNSET) {
mediaFormat.setFloat(MediaFormat.KEY_OPERATING_RATE, codecOperatingRate); mediaFormat.setFloat(MediaFormat.KEY_OPERATING_RATE, codecOperatingRate);
@ -2337,7 +2339,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
mediaFormat.setFeatureEnabled(CodecCapabilities.FEATURE_TunneledPlayback, true); mediaFormat.setFeatureEnabled(CodecCapabilities.FEATURE_TunneledPlayback, true);
mediaFormat.setInteger(MediaFormat.KEY_AUDIO_SESSION_ID, tunnelingAudioSessionId); mediaFormat.setInteger(MediaFormat.KEY_AUDIO_SESSION_ID, tunnelingAudioSessionId);
} }
if (Util.SDK_INT >= 35) { if (SDK_INT >= 35) {
mediaFormat.setInteger(MediaFormat.KEY_IMPORTANCE, max(0, -rendererPriority)); mediaFormat.setInteger(MediaFormat.KEY_IMPORTANCE, max(0, -rendererPriority));
} }
return mediaFormat; return mediaFormat;
@ -2557,7 +2559,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
} }
private static boolean evaluateDeviceNeedsSetOutputSurfaceWorkaround() { private static boolean evaluateDeviceNeedsSetOutputSurfaceWorkaround() {
if (Util.SDK_INT <= 28) { if (SDK_INT <= 28) {
// Workaround for MiTV and MiBox devices which have been observed broken up to API 28. // Workaround for MiTV and MiBox devices which have been observed broken up to API 28.
// https://github.com/google/ExoPlayer/issues/5169, // https://github.com/google/ExoPlayer/issues/5169,
// https://github.com/google/ExoPlayer/issues/6899. // https://github.com/google/ExoPlayer/issues/6899.
@ -2578,7 +2580,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
break; // Do nothing. break; // Do nothing.
} }
} }
if (Util.SDK_INT <= 27 && "HWEML".equals(Build.DEVICE)) { if (SDK_INT <= 27 && "HWEML".equals(Build.DEVICE)) {
// Workaround for Huawei P20: // Workaround for Huawei P20:
// https://github.com/google/ExoPlayer/issues/4468#issuecomment-459291645. // https://github.com/google/ExoPlayer/issues/4468#issuecomment-459291645.
return true; return true;
@ -2598,7 +2600,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
default: default:
break; // Do nothing. break; // Do nothing.
} }
if (Util.SDK_INT <= 26) { if (SDK_INT <= 26) {
// In general, devices running API level 27 or later should be unaffected unless observed // In general, devices running API level 27 or later should be unaffected unless observed
// otherwise. Enable the workaround on a per-device basis. Works around: // otherwise. Enable the workaround on a per-device basis. Works around:
// https://github.com/google/ExoPlayer/issues/3236, // https://github.com/google/ExoPlayer/issues/3236,
@ -2795,7 +2797,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
// This was fixed in https://android-review.googlesource.com/1156807. // This was fixed in https://android-review.googlesource.com/1156807.
// //
// The workaround queues the event for subsequent processing, where the lock will not be held. // The workaround queues the event for subsequent processing, where the lock will not be held.
if (Util.SDK_INT < 30) { if (SDK_INT < 30) {
Message message = Message message =
Message.obtain( Message.obtain(
handler, handler,

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.video; package androidx.media3.exoplayer.video;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.VideoFrameProcessor.DROP_OUTPUT_FRAME; import static androidx.media3.common.VideoFrameProcessor.DROP_OUTPUT_FRAME;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
@ -114,6 +115,7 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
private VideoGraph.@MonotonicNonNull Factory videoGraphFactory; private VideoGraph.@MonotonicNonNull Factory videoGraphFactory;
private List<Effect> compositionEffects; private List<Effect> compositionEffects;
private VideoCompositorSettings compositorSettings; private VideoCompositorSettings compositorSettings;
private boolean enablePlaylistMode;
private Clock clock; private Clock clock;
private boolean requestOpenGlToneMapping; private boolean requestOpenGlToneMapping;
private boolean built; private boolean built;
@ -184,6 +186,36 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
return this; return this;
} }
/**
* Sets whether to enable playlist mode.
*
* <p>The default value is {@code false}.
*
* <p>This should only be set to {@code true} if there is a single {@linkplain
* PlaybackVideoGraphWrapper#getSink(int) input sink}.
*
* <p>If {@code true}, the {@link VideoGraph} output is considered as a playlist of clips. In
* this case, {@link PlaybackVideoGraphWrapper#startRendering()} and {@link
* PlaybackVideoGraphWrapper#stopRendering()} are called internally, when the corresponding
* methods are caller on the sink.
*
* <p>If {@code false}, the {@link VideoGraph} output is considered as a single clip. In this
* case, the caller is responsible for calling {@link
* PlaybackVideoGraphWrapper#startRendering()} and {@link
* PlaybackVideoGraphWrapper#stopRendering()}.
*
* @param enablePlaylistMode Whether to enable playlist mode.
* @return This builder, for convenience.
*/
@CanIgnoreReturnValue
public Builder setEnablePlaylistMode(boolean enablePlaylistMode) {
// This is set to true for ExoPlayer.setVideoEffects(). It's always false in
// CompositionPlayer, even if the Composition has a single sequence, because CompositionPlayer
// shouldn't behave differently for single and multi-sequence.
this.enablePlaylistMode = enablePlaylistMode;
return this;
}
/** /**
* Sets the {@link Clock} that will be used. * Sets the {@link Clock} that will be used.
* *
@ -270,6 +302,7 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
private final SparseArray<InputVideoSink> inputVideoSinks; private final SparseArray<InputVideoSink> inputVideoSinks;
private final List<Effect> compositionEffects; private final List<Effect> compositionEffects;
private final VideoCompositorSettings compositorSettings; private final VideoCompositorSettings compositorSettings;
private final boolean enablePlaylistMode;
private final VideoSink defaultVideoSink; private final VideoSink defaultVideoSink;
private final VideoSink.VideoFrameHandler videoFrameHandler; private final VideoSink.VideoFrameHandler videoFrameHandler;
private final Clock clock; private final Clock clock;
@ -320,6 +353,7 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
inputVideoSinks = new SparseArray<>(); inputVideoSinks = new SparseArray<>();
compositionEffects = builder.compositionEffects; compositionEffects = builder.compositionEffects;
compositorSettings = builder.compositorSettings; compositorSettings = builder.compositorSettings;
enablePlaylistMode = builder.enablePlaylistMode;
clock = builder.clock; clock = builder.clock;
defaultVideoSink = new DefaultVideoSink(builder.videoFrameReleaseControl, clock); defaultVideoSink = new DefaultVideoSink(builder.videoFrameReleaseControl, clock);
videoFrameHandler = videoFrameHandler =
@ -362,6 +396,16 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
listeners.remove(listener); listeners.remove(listener);
} }
/** Starts rendering to the output surface. */
public void startRendering() {
defaultVideoSink.startRendering();
}
/** Stops rendering to the output surface. */
public void stopRendering() {
defaultVideoSink.stopRendering();
}
// VideoSinkProvider methods // VideoSinkProvider methods
@Override @Override
@ -497,7 +541,7 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
if (requestOpenGlToneMapping) { if (requestOpenGlToneMapping) {
outputColorInfo = ColorInfo.SDR_BT709_LIMITED; outputColorInfo = ColorInfo.SDR_BT709_LIMITED;
} else if (inputColorInfo.colorTransfer == C.COLOR_TRANSFER_HLG } else if (inputColorInfo.colorTransfer == C.COLOR_TRANSFER_HLG
&& Util.SDK_INT < 34 && SDK_INT < 34
&& GlUtil.isBt2020PqExtensionSupported()) { && GlUtil.isBt2020PqExtensionSupported()) {
// PQ SurfaceView output is supported from API 33, but HLG output is supported from API // PQ SurfaceView output is supported from API 33, but HLG output is supported from API
// 34. Therefore, convert HLG to PQ if PQ is supported, so that HLG input can be displayed // 34. Therefore, convert HLG to PQ if PQ is supported, so that HLG input can be displayed
@ -506,8 +550,7 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
inputColorInfo.buildUpon().setColorTransfer(C.COLOR_TRANSFER_ST2084).build(); inputColorInfo.buildUpon().setColorTransfer(C.COLOR_TRANSFER_ST2084).build();
// Force OpenGL tone mapping if the GL extension required to output HDR colors is not // Force OpenGL tone mapping if the GL extension required to output HDR colors is not
// available. OpenGL tone mapping is only supported on API 29+. // available. OpenGL tone mapping is only supported on API 29+.
} else if (!GlUtil.isColorTransferSupported(inputColorInfo.colorTransfer) } else if (!GlUtil.isColorTransferSupported(inputColorInfo.colorTransfer) && SDK_INT >= 29) {
&& Util.SDK_INT >= 29) {
Log.w( Log.w(
TAG, TAG,
Util.formatInvariant( Util.formatInvariant(
@ -625,6 +668,10 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
checkStateNotNull(handler).post(() -> pendingFlushCount--); checkStateNotNull(handler).post(() -> pendingFlushCount--);
} }
private void joinPlayback(boolean renderNextFrameImmediately) {
defaultVideoSink.join(renderNextFrameImmediately);
}
private void setVideoFrameMetadataListener( private void setVideoFrameMetadataListener(
VideoFrameMetadataListener videoFrameMetadataListener) { VideoFrameMetadataListener videoFrameMetadataListener) {
this.videoFrameMetadataListener = videoFrameMetadataListener; this.videoFrameMetadataListener = videoFrameMetadataListener;
@ -704,12 +751,16 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
@Override @Override
public void startRendering() { public void startRendering() {
defaultVideoSink.startRendering(); if (enablePlaylistMode) {
PlaybackVideoGraphWrapper.this.startRendering();
}
} }
@Override @Override
public void stopRendering() { public void stopRendering() {
defaultVideoSink.stopRendering(); if (enablePlaylistMode) {
PlaybackVideoGraphWrapper.this.stopRendering();
}
} }
@Override @Override
@ -976,7 +1027,9 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
@Override @Override
public void join(boolean renderNextFrameImmediately) { public void join(boolean renderNextFrameImmediately) {
defaultVideoSink.join(renderNextFrameImmediately); if (enablePlaylistMode) {
PlaybackVideoGraphWrapper.this.joinPlayback(renderNextFrameImmediately);
}
} }
@Override @Override

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.video; package androidx.media3.exoplayer.video;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import android.content.Context; import android.content.Context;
@ -297,7 +298,7 @@ public final class VideoFrameReleaseHelper {
* called to update the surface. * called to update the surface.
*/ */
private void updateSurfaceMediaFrameRate() { private void updateSurfaceMediaFrameRate() {
if (Util.SDK_INT < 30 || surface == null) { if (SDK_INT < 30 || surface == null) {
return; return;
} }
@ -345,7 +346,7 @@ public final class VideoFrameReleaseHelper {
* unchanged. * unchanged.
*/ */
private void updateSurfacePlaybackFrameRate(boolean forceUpdate) { private void updateSurfacePlaybackFrameRate(boolean forceUpdate) {
if (Util.SDK_INT < 30 if (SDK_INT < 30
|| surface == null || surface == null
|| changeFrameRateStrategy == C.VIDEO_CHANGE_FRAME_RATE_STRATEGY_OFF) { || changeFrameRateStrategy == C.VIDEO_CHANGE_FRAME_RATE_STRATEGY_OFF) {
return; return;
@ -371,7 +372,7 @@ public final class VideoFrameReleaseHelper {
* C#VIDEO_CHANGE_FRAME_RATE_STRATEGY_OFF}. * C#VIDEO_CHANGE_FRAME_RATE_STRATEGY_OFF}.
*/ */
private void clearSurfaceFrameRate() { private void clearSurfaceFrameRate() {
if (Util.SDK_INT < 30 if (SDK_INT < 30
|| surface == null || surface == null
|| changeFrameRateStrategy == C.VIDEO_CHANGE_FRAME_RATE_STRATEGY_OFF || changeFrameRateStrategy == C.VIDEO_CHANGE_FRAME_RATE_STRATEGY_OFF
|| surfacePlaybackFrameRate == 0) { || surfacePlaybackFrameRate == 0) {

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer; package androidx.media3.exoplayer;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.exoplayer.AudioFocusManager.PLAYER_COMMAND_DO_NOT_PLAY; import static androidx.media3.exoplayer.AudioFocusManager.PLAYER_COMMAND_DO_NOT_PLAY;
import static androidx.media3.exoplayer.AudioFocusManager.PLAYER_COMMAND_PLAY_WHEN_READY; import static androidx.media3.exoplayer.AudioFocusManager.PLAYER_COMMAND_PLAY_WHEN_READY;
import static androidx.media3.exoplayer.AudioFocusManager.PLAYER_COMMAND_WAIT_FOR_CALLBACK; import static androidx.media3.exoplayer.AudioFocusManager.PLAYER_COMMAND_WAIT_FOR_CALLBACK;
@ -29,7 +30,6 @@ import android.os.Looper;
import androidx.media3.common.AudioAttributes; import androidx.media3.common.AudioAttributes;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Player; import androidx.media3.common.Player;
import androidx.media3.common.util.Util;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before; import org.junit.Before;
@ -550,7 +550,7 @@ public class AudioFocusManagerTest {
} }
private int getAudioFocusGainFromRequest(ShadowAudioManager.AudioFocusRequest audioFocusRequest) { private int getAudioFocusGainFromRequest(ShadowAudioManager.AudioFocusRequest audioFocusRequest) {
return Util.SDK_INT >= 26 return SDK_INT >= 26
? audioFocusRequest.audioFocusRequest.getFocusGain() ? audioFocusRequest.audioFocusRequest.getFocusGain()
: audioFocusRequest.durationHint; : audioFocusRequest.durationHint;
} }

View File

@ -18,6 +18,7 @@ package androidx.media3.exoplayer.audio;
import static android.media.AudioFormat.CHANNEL_OUT_5POINT1; import static android.media.AudioFormat.CHANNEL_OUT_5POINT1;
import static android.media.AudioFormat.CHANNEL_OUT_STEREO; import static android.media.AudioFormat.CHANNEL_OUT_STEREO;
import static android.media.AudioFormat.ENCODING_AC3; import static android.media.AudioFormat.ENCODING_AC3;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.test.utils.robolectric.ShadowMediaCodecConfig.CODEC_INFO_AAC; import static androidx.media3.test.utils.robolectric.ShadowMediaCodecConfig.CODEC_INFO_AAC;
import static androidx.media3.test.utils.robolectric.ShadowMediaCodecConfig.CODEC_INFO_AC3; import static androidx.media3.test.utils.robolectric.ShadowMediaCodecConfig.CODEC_INFO_AC3;
@ -44,7 +45,6 @@ import androidx.media3.common.MimeTypes;
import androidx.media3.common.Player; import androidx.media3.common.Player;
import androidx.media3.common.Tracks; import androidx.media3.common.Tracks;
import androidx.media3.common.Tracks.Group; import androidx.media3.common.Tracks.Group;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.DecoderCounters; import androidx.media3.exoplayer.DecoderCounters;
import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.Renderer; import androidx.media3.exoplayer.Renderer;
@ -462,7 +462,7 @@ public class AudioCapabilitiesEndToEndTest {
.setFlags(0) .setFlags(0)
.build()); .build());
directPlaybackDevice = createDirectPlaybackDevice(ENCODING_AC3, CHANNEL_OUT_5POINT1); directPlaybackDevice = createDirectPlaybackDevice(ENCODING_AC3, CHANNEL_OUT_5POINT1);
if (Util.SDK_INT >= 33) { if (SDK_INT >= 33) {
shadowOf(audioManager).addOutputDeviceWithDirectProfiles(checkNotNull(directPlaybackDevice)); shadowOf(audioManager).addOutputDeviceWithDirectProfiles(checkNotNull(directPlaybackDevice));
} }
shadowOf(audioManager) shadowOf(audioManager)
@ -474,7 +474,7 @@ public class AudioCapabilitiesEndToEndTest {
ShadowAudioTrack.clearAllowedNonPcmEncodings(); ShadowAudioTrack.clearAllowedNonPcmEncodings();
ShadowAudioTrack.clearDirectPlaybackSupportedFormats(); ShadowAudioTrack.clearDirectPlaybackSupportedFormats();
if (directPlaybackDevice != null) { if (directPlaybackDevice != null) {
if (Util.SDK_INT >= 33) { if (SDK_INT >= 33) {
shadowOf(audioManager).removeOutputDeviceWithDirectProfiles(directPlaybackDevice); shadowOf(audioManager).removeOutputDeviceWithDirectProfiles(directPlaybackDevice);
} }
shadowOf(audioManager) shadowOf(audioManager)
@ -486,7 +486,7 @@ public class AudioCapabilitiesEndToEndTest {
private void setupDefaultPcmSupport() { private void setupDefaultPcmSupport() {
AudioDeviceInfoBuilder defaultDevice = AudioDeviceInfoBuilder defaultDevice =
AudioDeviceInfoBuilder.newBuilder().setType(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); AudioDeviceInfoBuilder.newBuilder().setType(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
if (Util.SDK_INT >= 33) { if (SDK_INT >= 33) {
defaultDevice.setProfiles(ImmutableList.of(createPcmProfile())); defaultDevice.setProfiles(ImmutableList.of(createPcmProfile()));
shadowOf(audioManager).addOutputDeviceWithDirectProfiles(defaultDevice.build()); shadowOf(audioManager).addOutputDeviceWithDirectProfiles(defaultDevice.build());
} else { } else {
@ -510,7 +510,7 @@ public class AudioCapabilitiesEndToEndTest {
private static AudioDeviceInfo createDirectPlaybackDevice(int encoding, int channelMask) { private static AudioDeviceInfo createDirectPlaybackDevice(int encoding, int channelMask) {
AudioDeviceInfoBuilder directPlaybackDevice = AudioDeviceInfoBuilder directPlaybackDevice =
AudioDeviceInfoBuilder.newBuilder().setType(AudioDeviceInfo.TYPE_HDMI); AudioDeviceInfoBuilder.newBuilder().setType(AudioDeviceInfo.TYPE_HDMI);
if (Util.SDK_INT >= 33) { if (SDK_INT >= 33) {
ImmutableList<AudioProfile> expectedProfiles = ImmutableList<AudioProfile> expectedProfiles =
ImmutableList.of( ImmutableList.of(
AudioProfileBuilder.newBuilder() AudioProfileBuilder.newBuilder()

View File

@ -16,6 +16,7 @@
package androidx.media3.exoplayer.audio; package androidx.media3.exoplayer.audio;
import static android.media.AudioFormat.CHANNEL_OUT_5POINT1; import static android.media.AudioFormat.CHANNEL_OUT_5POINT1;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.exoplayer.audio.AudioCapabilities.ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS; import static androidx.media3.exoplayer.audio.AudioCapabilities.ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS;
import static androidx.media3.exoplayer.audio.AudioCapabilities.getCapabilities; import static androidx.media3.exoplayer.audio.AudioCapabilities.getCapabilities;
@ -37,7 +38,6 @@ import androidx.media3.common.AudioAttributes;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Util;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -489,7 +489,7 @@ public class AudioCapabilitiesTest {
audioAttributes.getAudioAttributesV21().audioAttributes); audioAttributes.getAudioAttributesV21().audioAttributes);
AudioDeviceInfoBuilder deviceInfoBuilder = AudioDeviceInfoBuilder deviceInfoBuilder =
AudioDeviceInfoBuilder.newBuilder().setType(AudioDeviceInfo.TYPE_HDMI); AudioDeviceInfoBuilder.newBuilder().setType(AudioDeviceInfo.TYPE_HDMI);
if (Util.SDK_INT >= 33) { if (SDK_INT >= 33) {
ImmutableList<AudioProfile> expectedProfiles = ImmutableList<AudioProfile> expectedProfiles =
ImmutableList.of( ImmutableList.of(
AudioProfileBuilder.newBuilder() AudioProfileBuilder.newBuilder()

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.audio; package androidx.media3.exoplayer.audio;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.exoplayer.audio.AudioSink.SINK_FORMAT_SUPPORTED_DIRECTLY; import static androidx.media3.exoplayer.audio.AudioSink.SINK_FORMAT_SUPPORTED_DIRECTLY;
import static androidx.media3.exoplayer.audio.AudioSink.SINK_FORMAT_SUPPORTED_WITH_TRANSCODING; import static androidx.media3.exoplayer.audio.AudioSink.SINK_FORMAT_SUPPORTED_WITH_TRANSCODING;
@ -774,7 +775,7 @@ public final class DefaultAudioSinkTest {
// Adding the permission to the test AndroidManifest.xml doesn't work to appease lint. // Adding the permission to the test AndroidManifest.xml doesn't work to appease lint.
@SuppressWarnings({"StickyBroadcast", "MissingPermission"}) @SuppressWarnings({"StickyBroadcast", "MissingPermission"})
private void addHdmiDevice() { private void addHdmiDevice() {
if (Util.SDK_INT >= 23) { if (SDK_INT >= 23) {
// AudioFormat.getChannelIndexMask() in the implementation of // AudioFormat.getChannelIndexMask() in the implementation of
// ShadowAudioTrack.addDirectPlaybackSupport requires API 23+. // ShadowAudioTrack.addDirectPlaybackSupport requires API 23+.
// https://cs.android.com/android/platform/superproject/main/+/main:external/robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioTrack.java?q=format.getChannelIndexMask() // https://cs.android.com/android/platform/superproject/main/+/main:external/robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioTrack.java?q=format.getChannelIndexMask()
@ -794,7 +795,7 @@ public final class DefaultAudioSinkTest {
// https://cs.android.com/android/platform/superproject/main/+/main:external/robolectric/shadows/framework/src/main/java/org/robolectric/shadows/AudioDeviceInfoBuilder.java?q=VERSION_CODES.M // https://cs.android.com/android/platform/superproject/main/+/main:external/robolectric/shadows/framework/src/main/java/org/robolectric/shadows/AudioDeviceInfoBuilder.java?q=VERSION_CODES.M
AudioDeviceInfoBuilder hdmiDeviceBuilder = AudioDeviceInfoBuilder hdmiDeviceBuilder =
AudioDeviceInfoBuilder.newBuilder().setType(AudioDeviceInfo.TYPE_HDMI); AudioDeviceInfoBuilder.newBuilder().setType(AudioDeviceInfo.TYPE_HDMI);
if (Util.SDK_INT >= 33) { if (SDK_INT >= 33) {
ImmutableList<AudioProfile> expectedProfiles = ImmutableList<AudioProfile> expectedProfiles =
ImmutableList.of( ImmutableList.of(
AudioProfileBuilder.newBuilder() AudioProfileBuilder.newBuilder()
@ -833,7 +834,7 @@ public final class DefaultAudioSinkTest {
// Adding the permission to the test AndroidManifest.xml doesn't work to appease lint. // Adding the permission to the test AndroidManifest.xml doesn't work to appease lint.
@SuppressWarnings({"StickyBroadcast", "MissingPermission"}) @SuppressWarnings({"StickyBroadcast", "MissingPermission"})
private void removeHdmiDevice() { private void removeHdmiDevice() {
if (Util.SDK_INT >= 23 && hdmiDevice != null) { if (SDK_INT >= 23 && hdmiDevice != null) {
ShadowAudioTrack.clearAllowedNonPcmEncodings(); ShadowAudioTrack.clearAllowedNonPcmEncodings();
ShadowAudioTrack.clearDirectPlaybackSupportedFormats(); ShadowAudioTrack.clearDirectPlaybackSupportedFormats();
getShadowAudioManager().removeOutputDeviceWithDirectProfiles(hdmiDevice); getShadowAudioManager().removeOutputDeviceWithDirectProfiles(hdmiDevice);
@ -851,7 +852,7 @@ public final class DefaultAudioSinkTest {
} }
private void addBluetoothDevice() { private void addBluetoothDevice() {
if (Util.SDK_INT >= 23) { if (SDK_INT >= 23) {
// For API 33+, AudioManager.getDirectProfilesForAttributes returns the AudioProfile for the // For API 33+, AudioManager.getDirectProfilesForAttributes returns the AudioProfile for the
// routed device. To simulate the Bluetooth is connected and routed, we need to remove the // routed device. To simulate the Bluetooth is connected and routed, we need to remove the
// profile of the HDMI device, which means that the HDMI device is no longer routed, but // profile of the HDMI device, which means that the HDMI device is no longer routed, but
@ -859,7 +860,7 @@ public final class DefaultAudioSinkTest {
removeHdmiDevice(); removeHdmiDevice();
AudioDeviceInfoBuilder bluetoothDeviceBuilder = AudioDeviceInfoBuilder bluetoothDeviceBuilder =
AudioDeviceInfoBuilder.newBuilder().setType(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP); AudioDeviceInfoBuilder.newBuilder().setType(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP);
if (Util.SDK_INT >= 33) { if (SDK_INT >= 33) {
bluetoothDeviceBuilder.setProfiles(ImmutableList.of(createPcmProfile())); bluetoothDeviceBuilder.setProfiles(ImmutableList.of(createPcmProfile()));
} }
bluetoothDevice = bluetoothDeviceBuilder.build(); bluetoothDevice = bluetoothDeviceBuilder.build();
@ -872,7 +873,7 @@ public final class DefaultAudioSinkTest {
} }
private void removeBluetoothDevice() { private void removeBluetoothDevice() {
if (Util.SDK_INT >= 23 && bluetoothDevice != null) { if (SDK_INT >= 23 && bluetoothDevice != null) {
// Add back the HDMI device back as the routed device to simulate that the bluetooth device // Add back the HDMI device back as the routed device to simulate that the bluetooth device
// has gone and is no longer routed. // has gone and is no longer routed.
addHdmiDevice(); addHdmiDevice();

View File

@ -17,6 +17,7 @@ package androidx.media3.exoplayer.upstream;
import static android.net.NetworkInfo.State.CONNECTED; import static android.net.NetworkInfo.State.CONNECTED;
import static android.net.NetworkInfo.State.DISCONNECTED; import static android.net.NetworkInfo.State.DISCONNECTED;
import static android.os.Build.VERSION.SDK_INT;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.content.Context; import android.content.Context;
@ -32,7 +33,6 @@ import android.telephony.TelephonyManager;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.util.BackgroundExecutor; import androidx.media3.common.util.BackgroundExecutor;
import androidx.media3.common.util.NetworkTypeObserver; import androidx.media3.common.util.NetworkTypeObserver;
import androidx.media3.common.util.Util;
import androidx.media3.datasource.DataSource; import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DataSpec; import androidx.media3.datasource.DataSpec;
import androidx.media3.test.utils.FakeClock; import androidx.media3.test.utils.FakeClock;
@ -796,7 +796,7 @@ public final class DefaultBandwidthMeterTest {
private void setActiveNetworkInfo(NetworkInfo networkInfo, int networkTypeOverride) { private void setActiveNetworkInfo(NetworkInfo networkInfo, int networkTypeOverride) {
// Set network info in ConnectivityManager and TelephonyDisplayInfo in TelephonyManager. // Set network info in ConnectivityManager and TelephonyDisplayInfo in TelephonyManager.
Shadows.shadowOf(connectivityManager).setActiveNetworkInfo(networkInfo); Shadows.shadowOf(connectivityManager).setActiveNetworkInfo(networkInfo);
if (Util.SDK_INT >= 31) { if (SDK_INT >= 31) {
Object displayInfo = Object displayInfo =
ShadowTelephonyManager.createTelephonyDisplayInfo( ShadowTelephonyManager.createTelephonyDisplayInfo(
networkInfo.getType(), networkTypeOverride); networkInfo.getType(), networkTypeOverride);

View File

@ -17,6 +17,7 @@ package androidx.media3.exoplayer.upstream.experimental;
import static android.net.NetworkInfo.State.CONNECTED; import static android.net.NetworkInfo.State.CONNECTED;
import static android.net.NetworkInfo.State.DISCONNECTED; import static android.net.NetworkInfo.State.DISCONNECTED;
import static android.os.Build.VERSION.SDK_INT;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.content.Context; import android.content.Context;
@ -32,7 +33,6 @@ import android.telephony.TelephonyManager;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.util.BackgroundExecutor; import androidx.media3.common.util.BackgroundExecutor;
import androidx.media3.common.util.NetworkTypeObserver; import androidx.media3.common.util.NetworkTypeObserver;
import androidx.media3.common.util.Util;
import androidx.media3.datasource.DataSource; import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DataSpec; import androidx.media3.datasource.DataSpec;
import androidx.media3.test.utils.FakeDataSource; import androidx.media3.test.utils.FakeDataSource;
@ -805,7 +805,7 @@ public final class ExperimentalBandwidthMeterTest {
private void setActiveNetworkInfo(NetworkInfo networkInfo, int networkTypeOverride) { private void setActiveNetworkInfo(NetworkInfo networkInfo, int networkTypeOverride) {
// Set network info in ConnectivityManager and TelephonyDisplayInfo in TelephonyManager. // Set network info in ConnectivityManager and TelephonyDisplayInfo in TelephonyManager.
Shadows.shadowOf(connectivityManager).setActiveNetworkInfo(networkInfo); Shadows.shadowOf(connectivityManager).setActiveNetworkInfo(networkInfo);
if (Util.SDK_INT >= 31) { if (SDK_INT >= 31) {
Object displayInfo = Object displayInfo =
ShadowTelephonyManager.createTelephonyDisplayInfo( ShadowTelephonyManager.createTelephonyDisplayInfo(
networkInfo.getType(), networkTypeOverride); networkInfo.getType(), networkTypeOverride);

View File

@ -19,6 +19,7 @@ import static android.media.MediaParser.PARAMETER_TS_IGNORE_AAC_STREAM;
import static android.media.MediaParser.PARAMETER_TS_IGNORE_AVC_STREAM; import static android.media.MediaParser.PARAMETER_TS_IGNORE_AVC_STREAM;
import static android.media.MediaParser.PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM; import static android.media.MediaParser.PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM;
import static android.media.MediaParser.PARAMETER_TS_MODE; import static android.media.MediaParser.PARAMETER_TS_MODE;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_EAGERLY_EXPOSE_TRACK_TYPE; import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_EAGERLY_EXPOSE_TRACK_TYPE;
import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_EXPOSE_CAPTION_FORMATS; import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_EXPOSE_CAPTION_FORMATS;
import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_IGNORE_TIMESTAMP_OFFSET; import static androidx.media3.exoplayer.source.mediaparser.MediaParserUtil.PARAMETER_IGNORE_TIMESTAMP_OFFSET;
@ -38,7 +39,6 @@ import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.analytics.PlayerId; import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.source.mediaparser.InputReaderAdapterV30; import androidx.media3.exoplayer.source.mediaparser.InputReaderAdapterV30;
import androidx.media3.exoplayer.source.mediaparser.MediaParserUtil; import androidx.media3.exoplayer.source.mediaparser.MediaParserUtil;
@ -270,7 +270,7 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt
mediaParser.setParameter(PARAMETER_TS_IGNORE_AVC_STREAM, true); mediaParser.setParameter(PARAMETER_TS_IGNORE_AVC_STREAM, true);
} }
} }
if (Util.SDK_INT >= 31) { if (SDK_INT >= 31) {
MediaParserUtil.setLogSessionIdOnMediaParser(mediaParser, playerId); MediaParserUtil.setLogSessionIdOnMediaParser(mediaParser, playerId);
} }
return mediaParser; return mediaParser;

View File

@ -83,6 +83,8 @@ import java.util.regex.Pattern;
// Lines are separated by an CRLF. // Lines are separated by an CRLF.
for (String line : RtspMessageUtil.splitRtspMessageBody(sdpString)) { for (String line : RtspMessageUtil.splitRtspMessageBody(sdpString)) {
line = line.trim();
if ("".equals(line)) { if ("".equals(line)) {
continue; continue;
} }

View File

@ -342,6 +342,25 @@ public class SessionDescriptionTest {
assertThat(sessionDescription.mediaDescriptionList.get(0).mediaTitle).isNull(); assertThat(sessionDescription.mediaDescriptionList.get(0).mediaTitle).isNull();
} }
@Test
public void parse_sdpStringWithTrailingWhitespace_succeeds() throws Exception {
String testMediaSdpInfo =
"v=0\r\n"
+ "o=MNobody 2890844526 2890842807 IN IP4 192.0.2.46\r\n"
+ "s=SDP Seminar\r\n"
+ "i=Sun Apr 20 12:59:09 2025\n\r\n"
+ "t=0 0\r\n"
+ "a=control:*\r\n"
+ "m=audio 3456 RTP/AVP 0\r\n"
+ "i=\r\n"
+ "a=rtpmap:97 AC3/44100 \r\n";
SessionDescription sessionDescription = SessionDescriptionParser.parse(testMediaSdpInfo);
assertThat(sessionDescription.sessionInfo).isEqualTo("Sun Apr 20 12:59:09 2025");
assertThat(sessionDescription.mediaDescriptionList.get(0).mediaTitle).isNull();
}
@Test @Test
public void parse_sdpStringWithEmptySessionAttribute_throwsParserException() { public void parse_sdpStringWithEmptySessionAttribute_throwsParserException() {
String testMediaSdpInfo = String testMediaSdpInfo =

View File

@ -15,6 +15,8 @@
*/ */
package androidx.media3.exoplayer.workmanager; package androidx.media3.exoplayer.workmanager;
import static android.os.Build.VERSION.SDK_INT;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
@ -49,7 +51,7 @@ public final class WorkManagerScheduler implements Scheduler {
private static final int SUPPORTED_REQUIREMENTS = private static final int SUPPORTED_REQUIREMENTS =
Requirements.NETWORK Requirements.NETWORK
| Requirements.NETWORK_UNMETERED | Requirements.NETWORK_UNMETERED
| (Util.SDK_INT >= 23 ? Requirements.DEVICE_IDLE : 0) | (SDK_INT >= 23 ? Requirements.DEVICE_IDLE : 0)
| Requirements.DEVICE_CHARGING | Requirements.DEVICE_CHARGING
| Requirements.DEVICE_STORAGE_NOT_LOW; | Requirements.DEVICE_STORAGE_NOT_LOW;
@ -105,7 +107,7 @@ public final class WorkManagerScheduler implements Scheduler {
} else { } else {
builder.setRequiredNetworkType(NetworkType.NOT_REQUIRED); builder.setRequiredNetworkType(NetworkType.NOT_REQUIRED);
} }
if (Util.SDK_INT >= 23 && requirements.isIdleRequired()) { if (SDK_INT >= 23 && requirements.isIdleRequired()) {
setRequiresDeviceIdle(builder); setRequiresDeviceIdle(builder);
} }
if (requirements.isChargingRequired()) { if (requirements.isChargingRequired()) {

View File

@ -28,6 +28,7 @@ import androidx.media3.common.ParserException;
import androidx.media3.common.util.ParsableBitArray; import androidx.media3.common.util.ParsableBitArray;
import androidx.media3.common.util.ParsableByteArray; import androidx.media3.common.util.ParsableByteArray;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.Target; import java.lang.annotation.Target;
@ -240,6 +241,7 @@ public final class Ac4Util {
presentationConfig = dataBitArray.readBits(5); // presentation_config presentationConfig = dataBitArray.readBits(5); // presentation_config
isSingleSubstreamGroup = (presentationConfig == 0x1f); isSingleSubstreamGroup = (presentationConfig == 0x1f);
} }
ac4Presentation.version = presentationVersion;
boolean addEmdfSubstreams; boolean addEmdfSubstreams;
if (!(isSingleSubstream || isSingleSubstreamGroup) && presentationConfig == 6) { if (!(isSingleSubstream || isSingleSubstreamGroup) && presentationConfig == 6) {
@ -437,6 +439,9 @@ public final class Ac4Util {
"Can't determine channel count of presentation."); "Can't determine channel count of presentation.");
} }
String codecString =
createCodecsString(bitstreamVersion, ac4Presentation.version, ac4Presentation.level);
return new Format.Builder() return new Format.Builder()
.setId(trackId) .setId(trackId)
.setSampleMimeType(MimeTypes.AUDIO_AC4) .setSampleMimeType(MimeTypes.AUDIO_AC4)
@ -444,6 +449,7 @@ public final class Ac4Util {
.setSampleRate(sampleRate) .setSampleRate(sampleRate)
.setDrmInitData(drmInitData) .setDrmInitData(drmInitData)
.setLanguage(language) .setLanguage(language)
.setCodecs(codecString)
.build(); .build();
} }
@ -631,6 +637,20 @@ public final class Ac4Util {
} }
} }
/**
* Create codec string based on bitstream version, presentation version and presentation level
*
* @param bitstreamVersion The bitstream version.
* @param presentationVersion The presentation version.
* @param mdcompat The mdcompat, i.e. presentation level.
* @return An AC-4 codec string built using the provided parameters.
*/
private static String createCodecsString(
int bitstreamVersion, int presentationVersion, int mdcompat) {
return Util.formatInvariant(
"ac-4.%02d.%02d.%02d", bitstreamVersion, presentationVersion, mdcompat);
}
/** /**
* Returns AC-4 format information given {@code data} containing a syncframe. The reading position * Returns AC-4 format information given {@code data} containing a syncframe. The reading position
* of {@code data} will be modified. * of {@code data} will be modified.
@ -767,6 +787,7 @@ public final class Ac4Util {
public int numOfUmxObjects; public int numOfUmxObjects;
public boolean hasBackChannels; public boolean hasBackChannels;
public int topChannelPairs; public int topChannelPairs;
public int version;
public int level; public int level;
private Ac4Presentation() { private Ac4Presentation() {
@ -775,6 +796,7 @@ public final class Ac4Util {
numOfUmxObjects = -1; numOfUmxObjects = -1;
hasBackChannels = true; hasBackChannels = true;
topChannelPairs = 2; topChannelPairs = 2;
version = 1;
level = 0; level = 0;
} }
} }

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.session; package androidx.media3.session;
import static android.os.Build.VERSION.SDK_INT;
import static android.view.KeyEvent.KEYCODE_MEDIA_FAST_FORWARD; import static android.view.KeyEvent.KEYCODE_MEDIA_FAST_FORWARD;
import static android.view.KeyEvent.KEYCODE_MEDIA_NEXT; import static android.view.KeyEvent.KEYCODE_MEDIA_NEXT;
import static android.view.KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE; import static android.view.KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
@ -43,7 +44,6 @@ import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import androidx.core.graphics.drawable.IconCompat; import androidx.core.graphics.drawable.IconCompat;
import androidx.media3.common.Player; import androidx.media3.common.Player;
import androidx.media3.common.util.Util;
/** The default {@link MediaNotification.ActionFactory}. */ /** The default {@link MediaNotification.ActionFactory}. */
/* package */ final class DefaultActionFactory implements MediaNotification.ActionFactory { /* package */ final class DefaultActionFactory implements MediaNotification.ActionFactory {
@ -114,7 +114,7 @@ import androidx.media3.common.util.Util;
MediaSession mediaSession, @Player.Command long command) { MediaSession mediaSession, @Player.Command long command) {
int keyCode = toKeyCode(command); int keyCode = toKeyCode(command);
Intent intent = getMediaButtonIntent(mediaSession, keyCode); Intent intent = getMediaButtonIntent(mediaSession, keyCode);
if (Util.SDK_INT >= 26 if (SDK_INT >= 26
&& command == COMMAND_PLAY_PAUSE && command == COMMAND_PLAY_PAUSE
&& !mediaSession.getPlayer().getPlayWhenReady()) { && !mediaSession.getPlayer().getPlayWhenReady()) {
return Api26.createForegroundServicePendingIntent(service, keyCode, intent); return Api26.createForegroundServicePendingIntent(service, keyCode, intent);
@ -123,7 +123,7 @@ import androidx.media3.common.util.Util;
service, service,
/* requestCode= */ keyCode, /* requestCode= */ keyCode,
intent, intent,
Util.SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0); SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0);
} }
} }
@ -136,7 +136,7 @@ import androidx.media3.common.util.Util;
service, service,
/* requestCode= */ KEYCODE_MEDIA_STOP, /* requestCode= */ KEYCODE_MEDIA_STOP,
intent, intent,
Util.SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0); SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0);
} }
private Intent getMediaButtonIntent(MediaSession mediaSession, int mediaKeyCode) { private Intent getMediaButtonIntent(MediaSession mediaSession, int mediaKeyCode) {
@ -178,8 +178,7 @@ import androidx.media3.common.util.Util;
service, service,
/* requestCode= */ ++customActionPendingIntentRequestCode, /* requestCode= */ ++customActionPendingIntentRequestCode,
intent, intent,
PendingIntent.FLAG_UPDATE_CURRENT PendingIntent.FLAG_UPDATE_CURRENT | (SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0));
| (Util.SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0));
} }
/** Returns whether {@code intent} was part of a {@link #createMediaAction media action}. */ /** Returns whether {@code intent} was part of a {@link #createMediaAction media action}. */

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.session; package androidx.media3.session;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.C.INDEX_UNSET; import static androidx.media3.common.C.INDEX_UNSET;
import static androidx.media3.common.Player.COMMAND_INVALID; import static androidx.media3.common.Player.COMMAND_INVALID;
import static androidx.media3.common.Player.COMMAND_PLAY_PAUSE; import static androidx.media3.common.Player.COMMAND_PLAY_PAUSE;
@ -371,7 +372,7 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi
.setShowWhen(displayElapsedTimeWithChronometer) .setShowWhen(displayElapsedTimeWithChronometer)
.setUsesChronometer(displayElapsedTimeWithChronometer); .setUsesChronometer(displayElapsedTimeWithChronometer);
if (Util.SDK_INT >= 31) { if (SDK_INT >= 31) {
Api31.setForegroundServiceBehavior(builder); Api31.setForegroundServiceBehavior(builder);
} }
@ -621,7 +622,7 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi
} }
private void ensureNotificationChannel() { private void ensureNotificationChannel() {
if (Util.SDK_INT < 26 || notificationManager.getNotificationChannel(channelId) != null) { if (SDK_INT < 26 || notificationManager.getNotificationChannel(channelId) != null) {
return; return;
} }
Api26.createNotificationChannel( Api26.createNotificationChannel(
@ -682,7 +683,7 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi
NotificationManager notificationManager, String channelId, String channelName) { NotificationManager notificationManager, String channelId, String channelName) {
NotificationChannel channel = NotificationChannel channel =
new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW); new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW);
if (Util.SDK_INT <= 27) { if (SDK_INT <= 27) {
// API 28+ will automatically hide the app icon 'badge' for notifications using // API 28+ will automatically hide the app icon 'badge' for notifications using
// Notification.MediaStyle, but we have to manually hide it for APIs 26 (when badges were // Notification.MediaStyle, but we have to manually hide it for APIs 26 (when badges were
// added) and 27. // added) and 27.

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.session; package androidx.media3.session;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import android.app.ForegroundServiceStartNotAllowedException; import android.app.ForegroundServiceStartNotAllowedException;
@ -25,14 +26,12 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.os.Build;
import android.view.KeyEvent; import android.view.KeyEvent;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -125,7 +124,7 @@ public class MediaButtonReceiver extends BroadcastReceiver {
// Only handle the intent once with the earliest key event that arrives. // Only handle the intent once with the earliest key event that arrives.
return; return;
} }
if (Util.SDK_INT >= 26) { if (SDK_INT >= 26) {
if (keyEvent.getKeyCode() != KeyEvent.KEYCODE_MEDIA_PLAY if (keyEvent.getKeyCode() != KeyEvent.KEYCODE_MEDIA_PLAY
&& keyEvent.getKeyCode() != KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE && keyEvent.getKeyCode() != KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
&& keyEvent.getKeyCode() != KeyEvent.KEYCODE_HEADSETHOOK) { && keyEvent.getKeyCode() != KeyEvent.KEYCODE_HEADSETHOOK) {
@ -159,8 +158,7 @@ public class MediaButtonReceiver extends BroadcastReceiver {
try { try {
ContextCompat.startForegroundService(context, intent); ContextCompat.startForegroundService(context, intent);
} catch (/* ForegroundServiceStartNotAllowedException */ IllegalStateException e) { } catch (/* ForegroundServiceStartNotAllowedException */ IllegalStateException e) {
if (Build.VERSION.SDK_INT >= 31 if (SDK_INT >= 31 && Api31.instanceOfForegroundServiceStartNotAllowedException(e)) {
&& Api31.instanceOfForegroundServiceStartNotAllowedException(e)) {
onForegroundServiceStartNotAllowedException( onForegroundServiceStartNotAllowedException(
intent, Api31.castToForegroundServiceStartNotAllowedException(e)); intent, Api31.castToForegroundServiceStartNotAllowedException(e));
} else { } else {

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.session; package androidx.media3.session;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkIndex; import static androidx.media3.common.util.Assertions.checkIndex;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
@ -415,7 +416,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
return; return;
} }
if (Util.SDK_INT >= 31 && platformController != null) { if (SDK_INT >= 31 && platformController != null) {
// Ensure the platform session gets allow-listed to start a foreground service after receiving // Ensure the platform session gets allow-listed to start a foreground service after receiving
// the play command. // the play command.
platformController platformController
@ -2533,7 +2534,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
private boolean requestConnectToService() { private boolean requestConnectToService() {
int flags = int flags =
Util.SDK_INT >= 29 SDK_INT >= 29
? Context.BIND_AUTO_CREATE | Context.BIND_INCLUDE_CAPABILITIES ? Context.BIND_AUTO_CREATE | Context.BIND_INCLUDE_CAPABILITIES
: Context.BIND_AUTO_CREATE; : Context.BIND_AUTO_CREATE;

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.session; package androidx.media3.session;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
@ -1232,7 +1233,7 @@ import org.checkerframework.checker.initialization.qual.UnderInitialization;
@Override @Override
public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) { public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) {
if (Util.SDK_INT < 23) { if (SDK_INT < 23) {
Log.w(TAG, "Session doesn't support setting mute state at API level less than 23"); Log.w(TAG, "Session doesn't support setting mute state at API level less than 23");
return; return;
} }
@ -1812,7 +1813,7 @@ import org.checkerframework.checker.initialization.qual.UnderInitialization;
@Nullable @Nullable
private static String getRoutingControllerId(MediaControllerCompat controllerCompat) { private static String getRoutingControllerId(MediaControllerCompat controllerCompat) {
if (Util.SDK_INT < 30) { if (SDK_INT < 30) {
return null; return null;
} }
android.media.session.MediaController fwkController = android.media.session.MediaController fwkController =

View File

@ -17,6 +17,7 @@ package androidx.media3.session;
import static android.app.Service.STOP_FOREGROUND_DETACH; import static android.app.Service.STOP_FOREGROUND_DETACH;
import static android.app.Service.STOP_FOREGROUND_REMOVE; import static android.app.Service.STOP_FOREGROUND_REMOVE;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS;
@ -443,7 +444,7 @@ import java.util.concurrent.TimeoutException;
} }
private void stopForeground(boolean removeNotifications) { private void stopForeground(boolean removeNotifications) {
if (Util.SDK_INT >= 24) { if (SDK_INT >= 24) {
Api24.stopForeground(mediaSessionService, removeNotifications); Api24.stopForeground(mediaSessionService, removeNotifications);
} else { } else {
mediaSessionService.stopForeground(removeNotifications); mediaSessionService.stopForeground(removeNotifications);

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.session; package androidx.media3.session;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.annotation.VisibleForTesting.PRIVATE; import static androidx.annotation.VisibleForTesting.PRIVATE;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
@ -798,7 +799,7 @@ public class MediaSession {
*/ */
@UnstableApi @UnstableApi
public final void setSessionActivity(@Nullable PendingIntent activityPendingIntent) { public final void setSessionActivity(@Nullable PendingIntent activityPendingIntent) {
if (Util.SDK_INT >= 31 && activityPendingIntent != null) { if (SDK_INT >= 31 && activityPendingIntent != null) {
checkArgument(Api31.isActivity(activityPendingIntent)); checkArgument(Api31.isActivity(activityPendingIntent));
} }
impl.setSessionActivity(activityPendingIntent); impl.setSessionActivity(activityPendingIntent);
@ -822,7 +823,7 @@ public class MediaSession {
@UnstableApi @UnstableApi
public final void setSessionActivity( public final void setSessionActivity(
ControllerInfo controller, @Nullable PendingIntent activityPendingIntent) { ControllerInfo controller, @Nullable PendingIntent activityPendingIntent) {
if (Util.SDK_INT >= 31 && activityPendingIntent != null) { if (SDK_INT >= 31 && activityPendingIntent != null) {
checkArgument(Api31.isActivity(activityPendingIntent)); checkArgument(Api31.isActivity(activityPendingIntent));
} }
impl.setSessionActivity(controller, activityPendingIntent); impl.setSessionActivity(controller, activityPendingIntent);
@ -2257,7 +2258,7 @@ public class MediaSession {
@CanIgnoreReturnValue @CanIgnoreReturnValue
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public BuilderT setSessionActivity(PendingIntent pendingIntent) { public BuilderT setSessionActivity(PendingIntent pendingIntent) {
if (Util.SDK_INT >= 31) { if (SDK_INT >= 31) {
checkArgument(Api31.isActivity(pendingIntent)); checkArgument(Api31.isActivity(pendingIntent));
} }
sessionActivity = checkNotNull(pendingIntent); sessionActivity = checkNotNull(pendingIntent);

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.session; package androidx.media3.session;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.Player.COMMAND_CHANGE_MEDIA_ITEMS; import static androidx.media3.common.Player.COMMAND_CHANGE_MEDIA_ITEMS;
import static androidx.media3.common.Player.COMMAND_PLAY_PAUSE; import static androidx.media3.common.Player.COMMAND_PLAY_PAUSE;
import static androidx.media3.common.Player.COMMAND_PREPARE; import static androidx.media3.common.Player.COMMAND_PREPARE;
@ -111,7 +112,7 @@ import org.checkerframework.checker.initialization.qual.Initialized;
private static final String TAG = "MediaSessionLegacyStub"; private static final String TAG = "MediaSessionLegacyStub";
private static final int PENDING_INTENT_FLAG_MUTABLE = private static final int PENDING_INTENT_FLAG_MUTABLE =
Util.SDK_INT >= 31 ? PendingIntent.FLAG_MUTABLE : 0; SDK_INT >= 31 ? PendingIntent.FLAG_MUTABLE : 0;
private static final String DEFAULT_MEDIA_SESSION_TAG_PREFIX = "androidx.media3.session.id"; private static final String DEFAULT_MEDIA_SESSION_TAG_PREFIX = "androidx.media3.session.id";
private static final String DEFAULT_MEDIA_SESSION_TAG_DELIM = "."; private static final String DEFAULT_MEDIA_SESSION_TAG_DELIM = ".";
@ -151,7 +152,7 @@ import org.checkerframework.checker.initialization.qual.Initialized;
broadcastReceiverComponentName = queryPackageManagerForMediaButtonReceiver(context); broadcastReceiverComponentName = queryPackageManagerForMediaButtonReceiver(context);
@Nullable ComponentName receiverComponentName = broadcastReceiverComponentName; @Nullable ComponentName receiverComponentName = broadcastReceiverComponentName;
boolean isReceiverComponentAService = false; boolean isReceiverComponentAService = false;
if (receiverComponentName == null || Util.SDK_INT < 31) { if (receiverComponentName == null || SDK_INT < 31) {
// Below API 26, media button events are sent to the receiver at runtime also. We always want // Below API 26, media button events are sent to the receiver at runtime also. We always want
// these to arrive at the service at runtime. release() then set the receiver for restart if // these to arrive at the service at runtime. release() then set the receiver for restart if
// available. // available.
@ -185,7 +186,7 @@ import org.checkerframework.checker.initialization.qual.Initialized;
intent.setComponent(receiverComponentName); intent.setComponent(receiverComponentName);
mediaButtonIntent = mediaButtonIntent =
isReceiverComponentAService isReceiverComponentAService
? (Util.SDK_INT >= 26 ? (SDK_INT >= 26
? PendingIntent.getForegroundService( ? PendingIntent.getForegroundService(
context, /* requestCode= */ 0, intent, PENDING_INTENT_FLAG_MUTABLE) context, /* requestCode= */ 0, intent, PENDING_INTENT_FLAG_MUTABLE)
: PendingIntent.getService( : PendingIntent.getService(
@ -203,10 +204,10 @@ import org.checkerframework.checker.initialization.qual.Initialized;
new MediaSessionCompat( new MediaSessionCompat(
context, context,
sessionCompatId, sessionCompatId,
Util.SDK_INT < 31 ? receiverComponentName : null, SDK_INT < 31 ? receiverComponentName : null,
Util.SDK_INT < 31 ? mediaButtonIntent : null, SDK_INT < 31 ? mediaButtonIntent : null,
/* sessionInfo= */ tokenExtras); /* sessionInfo= */ tokenExtras);
if (Util.SDK_INT >= 31 && broadcastReceiverComponentName != null) { if (SDK_INT >= 31 && broadcastReceiverComponentName != null) {
Api31.setMediaButtonBroadcastReceiver(sessionCompat, broadcastReceiverComponentName); Api31.setMediaButtonBroadcastReceiver(sessionCompat, broadcastReceiverComponentName);
} }
@ -249,7 +250,7 @@ import org.checkerframework.checker.initialization.qual.Initialized;
@SuppressWarnings("PendingIntentMutability") // We can't use SaferPendingIntent. @SuppressWarnings("PendingIntentMutability") // We can't use SaferPendingIntent.
public void release() { public void release() {
if (Util.SDK_INT < 31) { if (SDK_INT < 31) {
if (broadcastReceiverComponentName == null) { if (broadcastReceiverComponentName == null) {
// No broadcast receiver available. Playback resumption not supported. // No broadcast receiver available. Playback resumption not supported.
setMediaButtonReceiver(sessionCompat, /* mediaButtonReceiverIntent= */ null); setMediaButtonReceiver(sessionCompat, /* mediaButtonReceiverIntent= */ null);

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.session; package androidx.media3.session;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkStateNotNull; import static androidx.media3.common.util.Assertions.checkStateNotNull;
@ -657,7 +658,7 @@ public abstract class MediaSessionService extends Service {
getMediaNotificationManager().shouldRunInForeground(startInForegroundWhenPaused); getMediaNotificationManager().shouldRunInForeground(startInForegroundWhenPaused);
onUpdateNotification(session, startInForegroundRequired); onUpdateNotification(session, startInForegroundRequired);
} catch (/* ForegroundServiceStartNotAllowedException */ IllegalStateException e) { } catch (/* ForegroundServiceStartNotAllowedException */ IllegalStateException e) {
if ((Util.SDK_INT >= 31) && Api31.instanceOfForegroundServiceStartNotAllowedException(e)) { if ((SDK_INT >= 31) && Api31.instanceOfForegroundServiceStartNotAllowedException(e)) {
Log.e(TAG, "Failed to start foreground", e); Log.e(TAG, "Failed to start foreground", e);
onForegroundServiceStartNotAllowedException(); onForegroundServiceStartNotAllowedException();
return false; return false;
@ -733,7 +734,7 @@ public abstract class MediaSessionService extends Service {
@Override @Override
public boolean onPlayRequested(MediaSession session) { public boolean onPlayRequested(MediaSession session) {
if (Util.SDK_INT < 31 || Util.SDK_INT >= 33) { if (SDK_INT < 31 || SDK_INT >= 33) {
return true; return true;
} }
// Check if service can start foreground successfully on Android 12 and 12L. // Check if service can start foreground successfully on Android 12 and 12L.

View File

@ -16,6 +16,7 @@
package androidx.media3.session; package androidx.media3.session;
import static android.Manifest.permission.MEDIA_CONTENT_CONTROL; import static android.Manifest.permission.MEDIA_CONTENT_CONTROL;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.core.app.NotificationCompat.COLOR_DEFAULT; import static androidx.core.app.NotificationCompat.COLOR_DEFAULT;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
@ -33,7 +34,6 @@ import androidx.core.app.NotificationBuilderWithBuilderAccessor;
import androidx.core.graphics.drawable.IconCompat; import androidx.core.graphics.drawable.IconCompat;
import androidx.media3.common.util.NullableType; import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@ -200,7 +200,7 @@ public class MediaStyleNotificationHelper {
if (actionsToShowInCompact != null) { if (actionsToShowInCompact != null) {
style.setShowActionsInCompactView(actionsToShowInCompact); style.setShowActionsInCompactView(actionsToShowInCompact);
} }
if (Util.SDK_INT >= 34 && remoteDeviceName != null) { if (SDK_INT >= 34 && remoteDeviceName != null) {
Api34Impl.setRemotePlaybackInfo( Api34Impl.setRemotePlaybackInfo(
style, remoteDeviceName, remoteDeviceIconRes, remoteDeviceIntent); style, remoteDeviceName, remoteDeviceIconRes, remoteDeviceIntent);
builder.getBuilder().setStyle(style); builder.getBuilder().setStyle(style);
@ -332,7 +332,7 @@ public class MediaStyleNotificationHelper {
@Override @Override
public void apply(NotificationBuilderWithBuilderAccessor builder) { public void apply(NotificationBuilderWithBuilderAccessor builder) {
if (Util.SDK_INT < 24) { if (SDK_INT < 24) {
super.apply(builder); super.apply(builder);
return; return;
} }
@ -341,7 +341,7 @@ public class MediaStyleNotificationHelper {
if (actionsToShowInCompact != null) { if (actionsToShowInCompact != null) {
style.setShowActionsInCompactView(actionsToShowInCompact); style.setShowActionsInCompactView(actionsToShowInCompact);
} }
if (Util.SDK_INT >= 34 && remoteDeviceName != null) { if (SDK_INT >= 34 && remoteDeviceName != null) {
Api34Impl.setRemotePlaybackInfo( Api34Impl.setRemotePlaybackInfo(
style, remoteDeviceName, remoteDeviceIconRes, remoteDeviceIntent); style, remoteDeviceName, remoteDeviceIconRes, remoteDeviceIntent);
builder.getBuilder().setStyle(style); builder.getBuilder().setStyle(style);
@ -357,7 +357,7 @@ public class MediaStyleNotificationHelper {
@Nullable @Nullable
@SuppressWarnings("nullness:override.return") // NotificationCompat doesn't annotate @Nullable @SuppressWarnings("nullness:override.return") // NotificationCompat doesn't annotate @Nullable
public RemoteViews makeContentView(NotificationBuilderWithBuilderAccessor builder) { public RemoteViews makeContentView(NotificationBuilderWithBuilderAccessor builder) {
if (Util.SDK_INT >= 24) { if (SDK_INT >= 24) {
// No custom content view required // No custom content view required
return null; return null;
} }
@ -385,7 +385,7 @@ public class MediaStyleNotificationHelper {
@Nullable @Nullable
@SuppressWarnings("nullness:override.return") // NotificationCompat doesn't annotate @Nullable @SuppressWarnings("nullness:override.return") // NotificationCompat doesn't annotate @Nullable
public RemoteViews makeBigContentView(NotificationBuilderWithBuilderAccessor builder) { public RemoteViews makeBigContentView(NotificationBuilderWithBuilderAccessor builder) {
if (Util.SDK_INT >= 24) { if (SDK_INT >= 24) {
// No custom big content view required // No custom big content view required
return null; return null;
} }
@ -414,7 +414,7 @@ public class MediaStyleNotificationHelper {
@Nullable @Nullable
@SuppressWarnings("nullness:override.return") // NotificationCompat doesn't annotate @Nullable @SuppressWarnings("nullness:override.return") // NotificationCompat doesn't annotate @Nullable
public RemoteViews makeHeadsUpContentView(NotificationBuilderWithBuilderAccessor builder) { public RemoteViews makeHeadsUpContentView(NotificationBuilderWithBuilderAccessor builder) {
if (Util.SDK_INT >= 24) { if (SDK_INT >= 24) {
// No custom heads up content view required // No custom heads up content view required
return null; return null;
} }

View File

@ -15,13 +15,13 @@
*/ */
package androidx.media3.session.legacy; package androidx.media3.session.legacy;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.annotation.RestrictTo.Scope.LIBRARY; import static androidx.annotation.RestrictTo.Scope.LIBRARY;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import androidx.annotation.RestrictTo; import androidx.annotation.RestrictTo;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.checkerframework.checker.nullness.qual.PolyNull; import org.checkerframework.checker.nullness.qual.PolyNull;
@ -88,7 +88,7 @@ public final class LegacyParcelableUtil {
// TODO: b/335804969 - Remove this workaround once the bug fix is in the androidx.media dependency // TODO: b/335804969 - Remove this workaround once the bug fix is in the androidx.media dependency
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static <T> T maybeApplyMediaDescriptionParcelableBugWorkaround(T value) { private static <T> T maybeApplyMediaDescriptionParcelableBugWorkaround(T value) {
if (Util.SDK_INT < 21 || Util.SDK_INT >= 23) { if (SDK_INT >= 23) {
return value; return value;
} }
if (value instanceof android.support.v4.media.MediaBrowserCompat.MediaItem) { if (value instanceof android.support.v4.media.MediaBrowserCompat.MediaItem) {

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.session; package androidx.media3.session;
import static android.os.Build.VERSION.SDK_INT;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.app.PendingIntent; import android.app.PendingIntent;
@ -23,7 +24,6 @@ import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import androidx.media3.common.MediaLibraryInfo; import androidx.media3.common.MediaLibraryInfo;
import androidx.media3.common.Player; import androidx.media3.common.Player;
import androidx.media3.common.util.Util;
import androidx.media3.test.utils.TestExoPlayerBuilder; import androidx.media3.test.utils.TestExoPlayerBuilder;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
@ -53,7 +53,7 @@ public class ConnectionStateTest {
context, context,
/* requestCode= */ 0, /* requestCode= */ 0,
new Intent(), new Intent(),
/* flags= */ Util.SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0), /* flags= */ SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0),
/* customLayout= */ ImmutableList.of( /* customLayout= */ ImmutableList.of(
new CommandButton.Builder(CommandButton.ICON_ARTIST) new CommandButton.Builder(CommandButton.ICON_ARTIST)
.setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT) .setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT)

View File

@ -15,6 +15,7 @@ track 0:
id = 1 id = 1
containerMimeType = audio/mp4 containerMimeType = audio/mp4
sampleMimeType = audio/ac4 sampleMimeType = audio/ac4
codecs = ac-4.02.02.00
maxInputSize = 622 maxInputSize = 622
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000

View File

@ -15,6 +15,7 @@ track 0:
id = 1 id = 1
containerMimeType = audio/mp4 containerMimeType = audio/mp4
sampleMimeType = audio/ac4 sampleMimeType = audio/ac4
codecs = ac-4.02.02.00
maxInputSize = 622 maxInputSize = 622
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000

View File

@ -15,6 +15,7 @@ track 0:
id = 1 id = 1
containerMimeType = audio/mp4 containerMimeType = audio/mp4
sampleMimeType = audio/ac4 sampleMimeType = audio/ac4
codecs = ac-4.02.02.00
maxInputSize = 622 maxInputSize = 622
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000

View File

@ -15,6 +15,7 @@ track 0:
id = 1 id = 1
containerMimeType = audio/mp4 containerMimeType = audio/mp4
sampleMimeType = audio/ac4 sampleMimeType = audio/ac4
codecs = ac-4.02.02.00
maxInputSize = 622 maxInputSize = 622
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000

View File

@ -15,6 +15,7 @@ track 0:
id = 1 id = 1
containerMimeType = audio/mp4 containerMimeType = audio/mp4
sampleMimeType = audio/ac4 sampleMimeType = audio/ac4
codecs = ac-4.02.02.00
maxInputSize = 622 maxInputSize = 622
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000

View File

@ -15,6 +15,7 @@ track 0:
id = 1 id = 1
containerMimeType = audio/mp4 containerMimeType = audio/mp4
sampleMimeType = audio/ac4 sampleMimeType = audio/ac4
codecs = ac-4.02.02.00
maxInputSize = 622 maxInputSize = 622
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000

View File

@ -15,6 +15,7 @@ track 0:
id = 1 id = 1
containerMimeType = audio/mp4 containerMimeType = audio/mp4
sampleMimeType = audio/ac4 sampleMimeType = audio/ac4
codecs = ac-4.02.02.00
maxInputSize = 622 maxInputSize = 622
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000

View File

@ -15,6 +15,7 @@ track 0:
id = 1 id = 1
containerMimeType = audio/mp4 containerMimeType = audio/mp4
sampleMimeType = audio/ac4 sampleMimeType = audio/ac4
codecs = ac-4.02.02.00
maxInputSize = 622 maxInputSize = 622
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000

View File

@ -15,6 +15,7 @@ track 0:
id = 1 id = 1
containerMimeType = audio/mp4 containerMimeType = audio/mp4
sampleMimeType = audio/ac4 sampleMimeType = audio/ac4
codecs = ac-4.02.02.00
maxInputSize = 622 maxInputSize = 622
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000

Some files were not shown because too many files have changed in this diff Show More