From 1bc8503a9bc55c8eba69c46ce6dfcd6a2c86d433 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 21 May 2020 12:34:23 +0100 Subject: [PATCH] Check DefaultAudioSink supports passthrough Previously if the AudioCapabilities reported that an encoding/channel count was supported, DefaultAudioSink could try to play it via passthrough. However, DefaultAudioSink does not support passthrough of every possible format (for example, it's likely that AAC passthrough does not work given it's never been tested and recent GitHub issues indicate that trying to use it leads to no audio being played). Add additional checks to make sure the encoding is in the list of encodings that are known to work with passthrough in DefaultAudioSink. issue:#7404 PiperOrigin-RevId: 312651358 --- RELEASENOTES.md | 3 +++ .../exoplayer2/audio/DefaultAudioSink.java | 22 +++++++++++++++---- .../audio/DefaultAudioSinkTest.java | 11 ++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) 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); }