diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 901d94a1cbc..f16ac3ee819 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -7,6 +7,8 @@ here ([#2826](https://github.com/google/ExoPlayer/issues/2826)). * Add options for controlling audio track selections to `DefaultTrackSelector` ([#3314](https://github.com/google/ExoPlayer/issues/3314)). +* Include channel count in audio capabilities check + ([#4690](https://github.com/google/ExoPlayer/issues/4690)). * Do not retry failed loads whose error is `FileNotFoundException`. ### 2.9.1 ### diff --git a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java index 13e3964c71e..f0b30baa8a9 100644 --- a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java +++ b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java @@ -145,12 +145,13 @@ public Format getOutputFormat() { } private boolean isOutputSupported(Format inputFormat) { - return shouldUseFloatOutput(inputFormat) || supportsOutputEncoding(C.ENCODING_PCM_16BIT); + return shouldUseFloatOutput(inputFormat) + || supportsOutput(inputFormat.channelCount, C.ENCODING_PCM_16BIT); } private boolean shouldUseFloatOutput(Format inputFormat) { Assertions.checkNotNull(inputFormat.sampleMimeType); - if (!enableFloatOutput || !supportsOutputEncoding(C.ENCODING_PCM_FLOAT)) { + if (!enableFloatOutput || !supportsOutput(inputFormat.channelCount, C.ENCODING_PCM_FLOAT)) { return false; } switch (inputFormat.sampleMimeType) { diff --git a/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/LibflacAudioRenderer.java b/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/LibflacAudioRenderer.java index fa66abbdc63..424fcbb2855 100644 --- a/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/LibflacAudioRenderer.java +++ b/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/LibflacAudioRenderer.java @@ -53,7 +53,7 @@ protected int supportsFormatInternal(DrmSessionManager drmSessio if (!FlacLibrary.isAvailable() || !MimeTypes.AUDIO_FLAC.equalsIgnoreCase(format.sampleMimeType)) { return FORMAT_UNSUPPORTED_TYPE; - } else if (!supportsOutputEncoding(C.ENCODING_PCM_16BIT)) { + } else if (!supportsOutput(format.channelCount, C.ENCODING_PCM_16BIT)) { return FORMAT_UNSUPPORTED_SUBTYPE; } else if (!supportsFormatDrm(drmSessionManager, format.drmInitData)) { return FORMAT_UNSUPPORTED_DRM; diff --git a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java index 57937b42828..e288339058a 100644 --- a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java +++ b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java @@ -78,7 +78,7 @@ protected int supportsFormatInternal(DrmSessionManager drmSessio if (!OpusLibrary.isAvailable() || !MimeTypes.AUDIO_OPUS.equalsIgnoreCase(format.sampleMimeType)) { return FORMAT_UNSUPPORTED_TYPE; - } else if (!supportsOutputEncoding(C.ENCODING_PCM_16BIT)) { + } else if (!supportsOutput(format.channelCount, C.ENCODING_PCM_16BIT)) { return FORMAT_UNSUPPORTED_SUBTYPE; } else if (!supportsFormatDrm(drmSessionManager, format.drmInitData)) { return FORMAT_UNSUPPORTED_DRM; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilities.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilities.java index 92d39dec654..6a5e58ef2a8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilities.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilities.java @@ -29,11 +29,11 @@ @TargetApi(21) public final class AudioCapabilities { - /** - * The minimum audio capabilities supported by all devices. - */ + private static final int DEFAULT_MAX_CHANNEL_COUNT = 8; + + /** The minimum audio capabilities supported by all devices. */ public static final AudioCapabilities DEFAULT_AUDIO_CAPABILITIES = - new AudioCapabilities(new int[] {AudioFormat.ENCODING_PCM_16BIT}, 2); + new AudioCapabilities(new int[] {AudioFormat.ENCODING_PCM_16BIT}, DEFAULT_MAX_CHANNEL_COUNT); /** * Returns the current audio capabilities for the device. @@ -52,8 +52,10 @@ public static AudioCapabilities getCapabilities(Context context) { if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 0) { return DEFAULT_AUDIO_CAPABILITIES; } - return new AudioCapabilities(intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS), - intent.getIntExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, 0)); + return new AudioCapabilities( + intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS), + intent.getIntExtra( + AudioManager.EXTRA_MAX_CHANNEL_COUNT, /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT)); } private final int[] supportedEncodings; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java index bf1dc3ca8ad..5e8efdc788d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java @@ -18,6 +18,7 @@ import android.media.AudioTrack; import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.PlaybackParameters; import java.nio.ByteBuffer; @@ -166,12 +167,13 @@ public WriteException(int errorCode) { void setListener(Listener listener); /** - * Returns whether it's possible to play audio in the specified encoding. + * Returns whether the sink supports the audio format. * - * @param encoding The audio encoding. - * @return Whether it's possible to play audio in the specified encoding. + * @param channelCount The number of channels, or {@link Format#NO_VALUE} if not known. + * @param encoding The audio encoding, or {@link Format#NO_VALUE} if not known. + * @return Whether the sink supports the audio format. */ - boolean isEncodingSupported(@C.Encoding int encoding); + boolean supportsOutput(int channelCount, @C.Encoding int encoding); /** * Returns the playback position in the stream starting at zero, in microseconds, or 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 7ba060ad76d..fc515dbdb34 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 @@ -376,14 +376,18 @@ public void setListener(Listener listener) { } @Override - public boolean isEncodingSupported(@C.Encoding int encoding) { + public boolean supportsOutput(int channelCount, @C.Encoding int encoding) { if (Util.isEncodingLinearPcm(encoding)) { // AudioTrack supports 16-bit integer PCM output in all platform API versions, and float // output from platform API version 21 only. Other integer PCM encodings are resampled by this - // sink to 16-bit PCM. + // sink to 16-bit PCM. We assume that the audio framework will downsample any number of + // 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); + return audioCapabilities != null + && audioCapabilities.supportsEncoding(encoding) + && (channelCount == Format.NO_VALUE + || channelCount <= audioCapabilities.getMaxChannelCount()); } } @@ -414,7 +418,7 @@ public void configure( isInputPcm = Util.isEncodingLinearPcm(inputEncoding); shouldConvertHighResIntPcmToFloat = enableConvertHighResIntPcmToFloat - && isEncodingSupported(C.ENCODING_PCM_32BIT) + && supportsOutput(channelCount, C.ENCODING_PCM_32BIT) && Util.isEncodingHighResolutionIntegerPcm(inputEncoding); if (isInputPcm) { pcmFrameSize = Util.getPcmFrameSize(inputEncoding, channelCount); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index d7206cd2c54..49c391c4cc8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -271,12 +271,14 @@ protected int supportsFormat(MediaCodecSelector mediaCodecSelector, } int tunnelingSupport = Util.SDK_INT >= 21 ? TUNNELING_SUPPORTED : TUNNELING_NOT_SUPPORTED; boolean supportsFormatDrm = supportsFormatDrm(drmSessionManager, format.drmInitData); - if (supportsFormatDrm && allowPassthrough(mimeType) + if (supportsFormatDrm + && allowPassthrough(format.channelCount, mimeType) && mediaCodecSelector.getPassthroughDecoderInfo() != null) { return ADAPTIVE_NOT_SEAMLESS | tunnelingSupport | FORMAT_HANDLED; } - if ((MimeTypes.AUDIO_RAW.equals(mimeType) && !audioSink.isEncodingSupported(format.pcmEncoding)) - || !audioSink.isEncodingSupported(C.ENCODING_PCM_16BIT)) { + if ((MimeTypes.AUDIO_RAW.equals(mimeType) + && !audioSink.supportsOutput(format.channelCount, format.pcmEncoding)) + || !audioSink.supportsOutput(format.channelCount, C.ENCODING_PCM_16BIT)) { // Assume the decoder outputs 16-bit PCM, unless the input is raw. return FORMAT_UNSUPPORTED_SUBTYPE; } @@ -315,7 +317,7 @@ protected int supportsFormat(MediaCodecSelector mediaCodecSelector, protected List getDecoderInfos( MediaCodecSelector mediaCodecSelector, Format format, boolean requiresSecureDecoder) throws DecoderQueryException { - if (allowPassthrough(format.sampleMimeType)) { + if (allowPassthrough(format.channelCount, format.sampleMimeType)) { MediaCodecInfo passthroughDecoderInfo = mediaCodecSelector.getPassthroughDecoderInfo(); if (passthroughDecoderInfo != null) { return Collections.singletonList(passthroughDecoderInfo); @@ -329,12 +331,13 @@ protected List getDecoderInfos( * This implementation returns true if the {@link AudioSink} indicates that encoded audio output * is supported. * + * @param channelCount The number of channels in the input media, or {@link Format#NO_VALUE} if + * not known. * @param mimeType The type of input media. * @return Whether passthrough playback is supported. */ - protected boolean allowPassthrough(String mimeType) { - @C.Encoding int encoding = MimeTypes.getEncoding(mimeType); - return encoding != C.ENCODING_INVALID && audioSink.isEncodingSupported(encoding); + protected boolean allowPassthrough(int channelCount, String mimeType) { + return audioSink.supportsOutput(channelCount, MimeTypes.getEncoding(mimeType)); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java index 3df38e35575..287cae9d413 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java @@ -249,13 +249,12 @@ protected abstract int supportsFormatInternal( DrmSessionManager drmSessionManager, Format format); /** - * Returns whether the audio sink can accept audio in the specified encoding. + * Returns whether the sink supports the audio format. * - * @param encoding The audio encoding. - * @return Whether the audio sink can accept audio in the specified encoding. + * @see AudioSink#supportsOutput(int, int) */ - protected final boolean supportsOutputEncoding(@C.Encoding int encoding) { - return audioSink.isEncodingSupported(encoding); + protected final boolean supportsOutput(int channelCount, @C.Encoding int encoding) { + return audioSink.supportsOutput(channelCount, encoding); } @Override