diff --git a/libraries/common/src/main/java/androidx/media3/common/audio/AudioProcessorChain.java b/libraries/common/src/main/java/androidx/media3/common/audio/AudioProcessorChain.java index 0c776c727f..2328044be7 100644 --- a/libraries/common/src/main/java/androidx/media3/common/audio/AudioProcessorChain.java +++ b/libraries/common/src/main/java/androidx/media3/common/audio/AudioProcessorChain.java @@ -15,6 +15,7 @@ */ package androidx.media3.common.audio; +import androidx.media3.common.Format; import androidx.media3.common.PlaybackParameters; import androidx.media3.common.util.UnstableApi; @@ -33,7 +34,7 @@ public interface AudioProcessorChain { * during initialization, but audio processors may change state to become active/inactive during * playback. */ - AudioProcessor[] getAudioProcessors(); + AudioProcessor[] getAudioProcessors(Format inputFormat); /** * Configures audio processors to apply the specified playback parameters immediately, returning @@ -50,7 +51,7 @@ public interface AudioProcessorChain { * value. Only called when processors have no input pending. * * @param skipSilenceEnabled Whether silences should be skipped in the audio stream. - * @return The new value. + * @return The value that was actually applied. */ boolean applySkipSilenceEnabled(boolean skipSilenceEnabled); diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultRenderersFactory.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultRenderersFactory.java index c7a64e21c5..78c80918ca 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultRenderersFactory.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultRenderersFactory.java @@ -233,8 +233,8 @@ public final DefaultRenderersFactory setMediaCodecSelector( /** * Sets whether floating point audio should be output when possible. * - *

Enabling floating point output disables audio processing, but may allow for higher quality - * audio output. + *

Enabling floating point output disables the default audio processing chain, but may allow + * for higher quality audio output. * *

The default value is {@code false}. * diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java index cedf500c07..9cd8d9b8fe 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java @@ -152,10 +152,14 @@ public interface AudioProcessorChain extends androidx.media3.common.audio.AudioP /** * The default audio processor chain, which applies a (possibly empty) chain of user-defined audio * processors followed by {@link SilenceSkippingAudioProcessor} and {@link SonicAudioProcessor}. + * + *

For backwards compatibility, no audio processors will be applied for PCM encodings other + * than 16-bit integer. */ @SuppressWarnings("deprecation") public static class DefaultAudioProcessorChain implements AudioProcessorChain { + private boolean formatSupported = false; private final AudioProcessor[] audioProcessors; private final SilenceSkippingAudioProcessor silenceSkippingAudioProcessor; private final SonicAudioProcessor sonicAudioProcessor; @@ -192,12 +196,22 @@ public DefaultAudioProcessorChain( } @Override - public AudioProcessor[] getAudioProcessors() { + public AudioProcessor[] getAudioProcessors(Format inputFormat) { + if (inputFormat.pcmEncoding != C.ENCODING_PCM_16BIT) { + formatSupported = false; + return new AudioProcessor[0]; + } + formatSupported = true; return audioProcessors; } @Override public PlaybackParameters applyPlaybackParameters(PlaybackParameters playbackParameters) { + if (!formatSupported) { + // We don't apply speed/pitch adjustment using an audio processor when outputting + // high-resolution PCM audio, because SonicAudioProcessor outputs 16-bit integer PCM. + return PlaybackParameters.DEFAULT; + } sonicAudioProcessor.setSpeed(playbackParameters.speed); sonicAudioProcessor.setPitch(playbackParameters.pitch); return playbackParameters; @@ -205,6 +219,11 @@ public PlaybackParameters applyPlaybackParameters(PlaybackParameters playbackPar @Override public boolean applySkipSilenceEnabled(boolean skipSilenceEnabled) { + if (!formatSupported) { + // We don't skip silence using an audio processor when outputting high-resolution PCM audio, + // because SilenceSkippingAudioProcessor only supports 16-bit integer PCM. + return false; + } silenceSkippingAudioProcessor.setEnabled(skipSilenceEnabled); return skipSilenceEnabled; } @@ -749,13 +768,16 @@ public void configure(AudioSinkConfig audioSinkConfig) throws ConfigurationExcep inputPcmFrameSize = Util.getPcmFrameSize(inputFormat.pcmEncoding, inputFormat.channelCount); ImmutableList.Builder pipelineProcessors = new ImmutableList.Builder<>(); + Format chainInputFormat; pipelineProcessors.addAll(availableAudioProcessors); if (shouldUseFloatOutput(inputFormat.pcmEncoding)) { pipelineProcessors.add(toFloatPcmAudioProcessor); + chainInputFormat = inputFormat.buildUpon().setPcmEncoding(C.ENCODING_PCM_FLOAT).build(); } else { pipelineProcessors.add(toInt16PcmAudioProcessor); - pipelineProcessors.add(audioProcessorChain.getAudioProcessors()); + chainInputFormat = inputFormat.buildUpon().setPcmEncoding(C.ENCODING_PCM_16BIT).build(); } + pipelineProcessors.add(audioProcessorChain.getAudioProcessors(chainInputFormat)); audioProcessingPipeline = new AudioProcessingPipeline(pipelineProcessors.build()); // If the underlying processors of the new pipeline are the same as the existing pipeline, @@ -1663,13 +1685,10 @@ private boolean shouldApplyAudioProcessorPlaybackParameters() { // We don't apply speed/pitch adjustment using an audio processor in the following cases: // - in tunneling mode, because audio processing can change the duration of audio yet the video // frame presentation times are currently not modified (see also - // https://github.com/google/ExoPlayer/issues/4803); + // https://github.com/google/ExoPlayer/issues/4803); and // - when playing encoded audio via passthrough/offload, because modifying the audio stream - // would require decoding/re-encoding; and - // - when outputting float PCM audio, because SonicAudioProcessor outputs 16-bit integer PCM. - return !tunneling - && configuration.isPcm() - && !shouldUseFloatOutput(configuration.inputFormat.pcmEncoding); + // would require decoding/re-encoding. + return !tunneling && configuration.isPcm(); } private boolean useAudioOutputPlaybackParams() { diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioSinkTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioSinkTest.java index 7d5237aafa..56cea39f07 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioSinkTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioSinkTest.java @@ -130,7 +130,7 @@ public void handlesBuffer_updatesPositionUsingAudioProcessorChain() throws Excep .setAudioProcessorChain( new AudioProcessorChain() { @Override - public AudioProcessor[] getAudioProcessors() { + public AudioProcessor[] getAudioProcessors(Format inputFormat) { return new AudioProcessor[0]; }