From 4455554e9eb6bf4d1527b24e7d4ecd72afbbef03 Mon Sep 17 00:00:00 2001 From: krocard Date: Thu, 16 Sep 2021 14:54:19 +0100 Subject: [PATCH] Use Android 12's AudioManager.getPlaybackOffloadSupport Previously gapless offload support was hardcoded to Pixel only. PiperOrigin-RevId: 397070378 --- .../java/com/google/android/exoplayer2/C.java | 20 ++++++++ .../exoplayer2/audio/DefaultAudioSink.java | 46 +++++++++++-------- 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/library/common/src/main/java/com/google/android/exoplayer2/C.java b/library/common/src/main/java/com/google/android/exoplayer2/C.java index 6a2755fe6c..ac7c5d8e04 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/C.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/C.java @@ -459,6 +459,26 @@ public final class C { public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE; + /** + * Playback offload mode. One of {@link #PLAYBACK_OFFLOAD_NOT_SUPPORTED},{@link + * PLAYBACK_OFFLOAD_SUPPORTED} or {@link PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED}. + */ + @IntDef({ + PLAYBACK_OFFLOAD_NOT_SUPPORTED, + PLAYBACK_OFFLOAD_SUPPORTED, + PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AudioManagerOffloadMode {} + /** See AudioManager#PLAYBACK_OFFLOAD_NOT_SUPPORTED */ + public static final int PLAYBACK_OFFLOAD_NOT_SUPPORTED = + AudioManager.PLAYBACK_OFFLOAD_NOT_SUPPORTED; + /** See AudioManager#PLAYBACK_OFFLOAD_SUPPORTED */ + public static final int PLAYBACK_OFFLOAD_SUPPORTED = AudioManager.PLAYBACK_OFFLOAD_SUPPORTED; + /** See AudioManager#PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED */ + public static final int PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED = + AudioManager.PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED; + /** * Flags which can apply to a buffer containing a media sample. Possible flag values are {@link * #BUFFER_FLAG_KEY_FRAME}, {@link #BUFFER_FLAG_END_OF_STREAM}, {@link #BUFFER_FLAG_LAST_SAMPLE}, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java index 376776575b..3592aef8bb 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java @@ -1619,33 +1619,41 @@ public final class DefaultAudioSink implements AudioSink { return false; } AudioFormat audioFormat = getAudioFormat(format.sampleRate, channelConfig, encoding); - if (!AudioManager.isOffloadedPlaybackSupported( - audioFormat, audioAttributes.getAudioAttributesV21())) { - return false; + + switch (getOffloadedPlaybackSupport(audioFormat, audioAttributes.getAudioAttributesV21())) { + case C.PLAYBACK_OFFLOAD_NOT_SUPPORTED: + return false; + case C.PLAYBACK_OFFLOAD_SUPPORTED: + boolean isGapless = format.encoderDelay != 0 || format.encoderPadding != 0; + boolean gaplessSupportRequired = offloadMode == OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED; + return !isGapless || !gaplessSupportRequired; + case C.PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED: + return true; + default: + throw new IllegalStateException(); } - boolean isGapless = format.encoderDelay != 0 || format.encoderPadding != 0; - boolean offloadRequiresGaplessSupport = offloadMode == OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED; - if (isGapless && offloadRequiresGaplessSupport && !isOffloadedGaplessPlaybackSupported()) { - return false; + } + + @C.AudioManagerOffloadMode + private int getOffloadedPlaybackSupport( + AudioFormat audioFormat, android.media.AudioAttributes audioAttributes) { + if (Util.SDK_INT >= 31) { + return AudioManager.getPlaybackOffloadSupport(audioFormat, audioAttributes); } - return true; + if (!AudioManager.isOffloadedPlaybackSupported(audioFormat, audioAttributes)) { + return C.PLAYBACK_OFFLOAD_NOT_SUPPORTED; + } + // Manual testing has shown that Pixels on Android 11 support gapless offload. + if (Util.SDK_INT == 30 && Util.MODEL.startsWith("Pixel")) { + return C.PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED; + } + return C.PLAYBACK_OFFLOAD_SUPPORTED; } private static boolean isOffloadedPlayback(AudioTrack audioTrack) { return Util.SDK_INT >= 29 && audioTrack.isOffloadedPlayback(); } - /** - * Returns whether the device supports gapless in offload playback. - * - *

Gapless offload is not supported by all devices and there is no API to query its support. As - * a result this detection is currently based on manual testing. - */ - // TODO(internal b/158191844): Add an SDK API to query offload gapless support. - private static boolean isOffloadedGaplessPlaybackSupported() { - return Util.SDK_INT >= 30 && Util.MODEL.startsWith("Pixel"); - } - private static int getMaximumEncodedRateBytesPerSecond(@C.Encoding int encoding) { switch (encoding) { case C.ENCODING_MP3: