diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 6dafa1530a..23e28024d8 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -157,6 +157,9 @@ and `AudioSink.handleBuffer` to allow batching multiple encoded frames in one buffer. * No longer use a `MediaCodec` in audio passthrough mode. + * Check `DefaultAudioSink` supports passthrough, in addition to checking + the `AudioCapabilities` + ([#7404](https://github.com/google/ExoPlayer/issues/7404)). * DASH: * Merge trick play adaptation sets (i.e., adaptation sets marked with `http://dashif.org/guidelines/trickmode`) into the same `TrackGroup` as 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 a1cdc6023c..6b06a7f678 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 @@ -417,10 +417,7 @@ public final class DefaultAudioSink implements AudioSink { // channels to the output device's required number of channels. return encoding != C.ENCODING_PCM_FLOAT || Util.SDK_INT >= 21; } else { - return audioCapabilities != null - && audioCapabilities.supportsEncoding(encoding) - && (channelCount == Format.NO_VALUE - || channelCount <= audioCapabilities.getMaxChannelCount()); + return isPassthroughPlaybackSupported(encoding, channelCount); } } @@ -1183,6 +1180,23 @@ public final class DefaultAudioSink implements AudioSink { : writtenEncodedFrames; } + private boolean isPassthroughPlaybackSupported(@C.Encoding int encoding, int channelCount) { + // Check for encodings that are known to work for passthrough with the implementation in this + // class. This avoids trying to use passthrough with an encoding where the device/app reports + // it's capable but it is untested or known to be broken (for example AAC-LC). + return audioCapabilities != null + && audioCapabilities.supportsEncoding(encoding) + && (encoding == C.ENCODING_AC3 + || encoding == C.ENCODING_E_AC3 + || encoding == C.ENCODING_E_AC3_JOC + || encoding == C.ENCODING_AC4 + || encoding == C.ENCODING_DTS + || encoding == C.ENCODING_DTS_HD + || encoding == C.ENCODING_DOLBY_TRUEHD) + && (channelCount == Format.NO_VALUE + || channelCount <= audioCapabilities.getMaxChannelCount()); + } + private static AudioTrack initializeKeepSessionIdAudioTrack(int audioSessionId) { int sampleRate = 4000; // Equal to private AudioTrack.MIN_SAMPLE_RATE. int channelConfig = AudioFormat.CHANNEL_OUT_MONO; diff --git a/library/core/src/test/java/com/google/android/exoplayer2/audio/DefaultAudioSinkTest.java b/library/core/src/test/java/com/google/android/exoplayer2/audio/DefaultAudioSinkTest.java index 6fb27f46c9..4636e6fc14 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/audio/DefaultAudioSinkTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/audio/DefaultAudioSinkTest.java @@ -215,6 +215,17 @@ public final class DefaultAudioSinkTest { .isTrue(); } + @Test + public void audioSinkWithAacAudioCapabilitiesWithoutOffload_doesNotSupportAacOutput() { + DefaultAudioSink defaultAudioSink = + new DefaultAudioSink( + new AudioCapabilities(new int[] {C.ENCODING_AAC_LC}, 2), new AudioProcessor[0]); + assertThat( + defaultAudioSink.supportsOutput( + CHANNEL_COUNT_STEREO, SAMPLE_RATE_44_1, C.ENCODING_AAC_LC)) + .isFalse(); + } + private void configureDefaultAudioSink(int channelCount) throws AudioSink.ConfigurationException { configureDefaultAudioSink(channelCount, /* trimStartFrames= */ 0, /* trimEndFrames= */ 0); }