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
This commit is contained in:
andrewlewis 2020-05-21 12:34:23 +01:00 committed by tonihei
parent 4384ef5b73
commit 1bc8503a9b
3 changed files with 32 additions and 4 deletions

View File

@ -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

View File

@ -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;

View File

@ -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);
}