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 22591de77e..18b05e8ecb 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 @@ -45,6 +45,8 @@ public final class LibflacAudioRenderer extends DecoderAudioRenderer { } /** + * Creates an instance. + * * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be * null if delivery of events is not required. * @param eventListener A listener of events. May be null if delivery of events is not required. @@ -58,6 +60,8 @@ public final class LibflacAudioRenderer extends DecoderAudioRenderer { } /** + * Creates an instance. + * * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be * null if delivery of events is not required. * @param eventListener A listener of events. May be null if delivery of events is not required. 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 b406dd5aad..39d8a216d8 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 @@ -21,6 +21,7 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.audio.AudioProcessor; import com.google.android.exoplayer2.audio.AudioRendererEventListener; +import com.google.android.exoplayer2.audio.AudioSink; import com.google.android.exoplayer2.audio.DecoderAudioRenderer; import com.google.android.exoplayer2.drm.ExoMediaCrypto; import com.google.android.exoplayer2.util.MimeTypes; @@ -44,6 +45,8 @@ public class LibopusAudioRenderer extends DecoderAudioRenderer { } /** + * Creates a new instance. + * * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be * null if delivery of events is not required. * @param eventListener A listener of events. May be null if delivery of events is not required. @@ -56,6 +59,21 @@ public class LibopusAudioRenderer extends DecoderAudioRenderer { super(eventHandler, eventListener, audioProcessors); } + /** + * Creates a new instance. + * + * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be + * null if delivery of events is not required. + * @param eventListener A listener of events. May be null if delivery of events is not required. + * @param audioSink The sink to which audio will be output. + */ + public LibopusAudioRenderer( + @Nullable Handler eventHandler, + @Nullable AudioRendererEventListener eventListener, + AudioSink audioSink) { + super(eventHandler, eventListener, audioSink); + } + @Override public String getName() { return TAG; diff --git a/library/core/proguard-rules.txt b/library/core/proguard-rules.txt index 9578bd869b..4fcfeb7162 100644 --- a/library/core/proguard-rules.txt +++ b/library/core/proguard-rules.txt @@ -31,15 +31,15 @@ } -dontnote com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer -keepclassmembers class com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer { - (android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioProcessor[]); + (android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioSink); } -dontnote com.google.android.exoplayer2.ext.flac.LibflacAudioRenderer -keepclassmembers class com.google.android.exoplayer2.ext.flac.LibflacAudioRenderer { - (android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioProcessor[]); + (android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioSink); } -dontnote com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer -keepclassmembers class com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer { - (android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioProcessor[]); + (android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioSink); } # Constructors accessed via reflection in DefaultDataSource diff --git a/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java index 3913922c3c..28e863bb19 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java @@ -20,9 +20,10 @@ import android.media.MediaCodec; import android.os.Handler; import android.os.Looper; import androidx.annotation.IntDef; +import androidx.annotation.Nullable; import com.google.android.exoplayer2.audio.AudioCapabilities; -import com.google.android.exoplayer2.audio.AudioProcessor; import com.google.android.exoplayer2.audio.AudioRendererEventListener; +import com.google.android.exoplayer2.audio.AudioSink; import com.google.android.exoplayer2.audio.DefaultAudioSink; import com.google.android.exoplayer2.audio.DefaultAudioSink.DefaultAudioProcessorChain; import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer; @@ -92,6 +93,7 @@ public class DefaultRenderersFactory implements RenderersFactory { private MediaCodecSelector mediaCodecSelector; private @MediaCodecRenderer.MediaCodecOperationMode int audioMediaCodecOperationMode; private @MediaCodecRenderer.MediaCodecOperationMode int videoMediaCodecOperationMode; + private boolean enableFloatOutput; private boolean enableOffload; /** @param context A {@link Context}. */ @@ -218,6 +220,22 @@ public class DefaultRenderersFactory implements RenderersFactory { return this; } + /** + * 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. + * + *

The default value is {@code false}. + * + * @param enableFloatOutput Whether to enable use of floating point audio output, if available. + * @return This factory, for convenience. + */ + public DefaultRenderersFactory setEnableAudioFloatOutput(boolean enableFloatOutput) { + this.enableFloatOutput = enableFloatOutput; + return this; + } + /** * Sets whether audio should be played using the offload path. * @@ -272,16 +290,18 @@ public class DefaultRenderersFactory implements RenderersFactory { videoRendererEventListener, allowedVideoJoiningTimeMs, renderersList); - buildAudioRenderers( - context, - extensionRendererMode, - mediaCodecSelector, - enableDecoderFallback, - buildAudioProcessors(), - eventHandler, - audioRendererEventListener, - enableOffload, - renderersList); + @Nullable AudioSink audioSink = buildAudioSink(context, enableFloatOutput, enableOffload); + if (audioSink != null) { + buildAudioRenderers( + context, + extensionRendererMode, + mediaCodecSelector, + enableDecoderFallback, + audioSink, + eventHandler, + audioRendererEventListener, + renderersList); + } buildTextRenderers(context, textRendererOutput, eventHandler.getLooper(), extensionRendererMode, renderersList); buildMetadataRenderers(context, metadataRendererOutput, eventHandler.getLooper(), @@ -427,12 +447,9 @@ public class DefaultRenderersFactory implements RenderersFactory { * @param enableDecoderFallback Whether to enable fallback to lower-priority decoders if decoder * initialization fails. This may result in using a decoder that is slower/less efficient than * the primary decoder. - * @param audioProcessors An array of {@link AudioProcessor}s that will process PCM audio buffers - * before output. May be empty. + * @param audioSink A sink to which the renderers will output. * @param eventHandler A handler to use when invoking event listeners and outputs. * @param eventListener An event listener. - * @param enableOffload Whether to enable use of audio offload for supported formats, if - * available. * @param out An array to which the built renderers should be appended. */ protected void buildAudioRenderers( @@ -440,10 +457,9 @@ public class DefaultRenderersFactory implements RenderersFactory { @ExtensionRendererMode int extensionRendererMode, MediaCodecSelector mediaCodecSelector, boolean enableDecoderFallback, - AudioProcessor[] audioProcessors, + AudioSink audioSink, Handler eventHandler, AudioRendererEventListener eventListener, - boolean enableOffload, ArrayList out) { MediaCodecAudioRenderer audioRenderer = new MediaCodecAudioRenderer( @@ -452,11 +468,7 @@ public class DefaultRenderersFactory implements RenderersFactory { enableDecoderFallback, eventHandler, eventListener, - new DefaultAudioSink( - AudioCapabilities.getCapabilities(context), - new DefaultAudioProcessorChain(audioProcessors), - /* enableFloatOutput= */ false, - enableOffload)); + audioSink); audioRenderer.experimental_setMediaCodecOperationMode(audioMediaCodecOperationMode); out.add(audioRenderer); @@ -476,10 +488,10 @@ public class DefaultRenderersFactory implements RenderersFactory { clazz.getConstructor( android.os.Handler.class, com.google.android.exoplayer2.audio.AudioRendererEventListener.class, - com.google.android.exoplayer2.audio.AudioProcessor[].class); + com.google.android.exoplayer2.audio.AudioSink.class); // LINT.ThenChange(../../../../../../../proguard-rules.txt) Renderer renderer = - (Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors); + (Renderer) constructor.newInstance(eventHandler, eventListener, audioSink); out.add(extensionRendererIndex++, renderer); Log.i(TAG, "Loaded LibopusAudioRenderer."); } catch (ClassNotFoundException e) { @@ -497,10 +509,10 @@ public class DefaultRenderersFactory implements RenderersFactory { clazz.getConstructor( android.os.Handler.class, com.google.android.exoplayer2.audio.AudioRendererEventListener.class, - com.google.android.exoplayer2.audio.AudioProcessor[].class); + com.google.android.exoplayer2.audio.AudioSink.class); // LINT.ThenChange(../../../../../../../proguard-rules.txt) Renderer renderer = - (Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors); + (Renderer) constructor.newInstance(eventHandler, eventListener, audioSink); out.add(extensionRendererIndex++, renderer); Log.i(TAG, "Loaded LibflacAudioRenderer."); } catch (ClassNotFoundException e) { @@ -519,10 +531,10 @@ public class DefaultRenderersFactory implements RenderersFactory { clazz.getConstructor( android.os.Handler.class, com.google.android.exoplayer2.audio.AudioRendererEventListener.class, - com.google.android.exoplayer2.audio.AudioProcessor[].class); + com.google.android.exoplayer2.audio.AudioSink.class); // LINT.ThenChange(../../../../../../../proguard-rules.txt) Renderer renderer = - (Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors); + (Renderer) constructor.newInstance(eventHandler, eventListener, audioSink); out.add(extensionRendererIndex++, renderer); Log.i(TAG, "Loaded FfmpegAudioRenderer."); } catch (ClassNotFoundException e) { @@ -595,10 +607,23 @@ public class DefaultRenderersFactory implements RenderersFactory { } /** - * Builds an array of {@link AudioProcessor}s that will process PCM audio before output. + * Builds an {@link AudioSink} to which the audio renderers will output. + * + * @param context The {@link Context} associated with the player. + * @param enableFloatOutput Whether to enable use of floating point audio output, if available. + * @param enableOffload Whether to enable use of audio offload for supported formats, if + * available. + * @return The {@link AudioSink} to which the audio renderers will output. May be {@code null} if + * no audio renderers are required. If {@code null} is returned then {@link + * #buildAudioRenderers} will not be called. */ - protected AudioProcessor[] buildAudioProcessors() { - return new AudioProcessor[0]; + @Nullable + protected AudioSink buildAudioSink( + Context context, boolean enableFloatOutput, boolean enableOffload) { + return new DefaultAudioSink( + AudioCapabilities.getCapabilities(context), + new DefaultAudioProcessorChain(), + enableFloatOutput, + enableOffload); } - } 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 4060e08726..1263a46ffe 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 @@ -365,14 +365,15 @@ public final class DefaultAudioSink implements AudioSink { * parameters adjustments. The instance passed in must not be reused in other sinks. * @param enableFloatOutput Whether to enable 32-bit float output. Where possible, 32-bit float * output will be used if the input is 32-bit float, and also if the input is high resolution - * (24-bit or 32-bit) integer PCM. Audio processing (for example, speed adjustment) will not - * be available when float output is in use. - * @param enableOffload Whether audio offloading is enabled. If an audio format can be both played + * (24-bit or 32-bit) integer PCM. Float output is supported from API level 21. Audio + * processing (for example, speed adjustment) will not be available when float output is in + * use. + * @param enableOffload Whether to enable audio offload. If an audio format can be both played * with offload and encoded audio passthrough, it will be played in offload. Audio offload is - * supported starting with API 29 ({@link android.os.Build.VERSION_CODES#Q}). Most Android - * devices can only support one offload {@link android.media.AudioTrack} at a time and can - * invalidate it at any time. Thus an app can never be guaranteed that it will be able to play - * in offload. + * supported from API level 29. Most Android devices can only support one offload {@link + * android.media.AudioTrack} at a time and can invalidate it at any time. Thus an app can + * never be guaranteed that it will be able to play in offload. Audio processing (for example, + * speed adjustment) will not be available when offload is in use. */ public DefaultAudioSink( @Nullable AudioCapabilities audioCapabilities,