DefaultRenderersFactory: Add setting to enable float output

This also renders https://github.com/google/ExoPlayer/pull/7625 redundant.

PiperOrigin-RevId: 321544195
This commit is contained in:
olly 2020-07-16 13:00:31 +01:00 committed by Oliver Woodman
parent 79c14cb801
commit 363a2a3b45
5 changed files with 90 additions and 42 deletions

View File

@ -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 * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required. * 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 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 * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required. * 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 eventListener A listener of events. May be null if delivery of events is not required.

View File

@ -21,6 +21,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.audio.AudioProcessor; import com.google.android.exoplayer2.audio.AudioProcessor;
import com.google.android.exoplayer2.audio.AudioRendererEventListener; 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.audio.DecoderAudioRenderer;
import com.google.android.exoplayer2.drm.ExoMediaCrypto; import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import com.google.android.exoplayer2.util.MimeTypes; 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 * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required. * 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 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); 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 @Override
public String getName() { public String getName() {
return TAG; return TAG;

View File

@ -31,15 +31,15 @@
} }
-dontnote com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer -dontnote com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer
-keepclassmembers class com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer { -keepclassmembers class com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer {
<init>(android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioProcessor[]); <init>(android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioSink);
} }
-dontnote com.google.android.exoplayer2.ext.flac.LibflacAudioRenderer -dontnote com.google.android.exoplayer2.ext.flac.LibflacAudioRenderer
-keepclassmembers class com.google.android.exoplayer2.ext.flac.LibflacAudioRenderer { -keepclassmembers class com.google.android.exoplayer2.ext.flac.LibflacAudioRenderer {
<init>(android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioProcessor[]); <init>(android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioSink);
} }
-dontnote com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer -dontnote com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer
-keepclassmembers class com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer { -keepclassmembers class com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer {
<init>(android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioProcessor[]); <init>(android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioSink);
} }
# Constructors accessed via reflection in DefaultDataSource # Constructors accessed via reflection in DefaultDataSource

View File

@ -20,9 +20,10 @@ import android.media.MediaCodec;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.audio.AudioCapabilities; 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.AudioRendererEventListener;
import com.google.android.exoplayer2.audio.AudioSink;
import com.google.android.exoplayer2.audio.DefaultAudioSink; import com.google.android.exoplayer2.audio.DefaultAudioSink;
import com.google.android.exoplayer2.audio.DefaultAudioSink.DefaultAudioProcessorChain; import com.google.android.exoplayer2.audio.DefaultAudioSink.DefaultAudioProcessorChain;
import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer; import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer;
@ -92,6 +93,7 @@ public class DefaultRenderersFactory implements RenderersFactory {
private MediaCodecSelector mediaCodecSelector; private MediaCodecSelector mediaCodecSelector;
private @MediaCodecRenderer.MediaCodecOperationMode int audioMediaCodecOperationMode; private @MediaCodecRenderer.MediaCodecOperationMode int audioMediaCodecOperationMode;
private @MediaCodecRenderer.MediaCodecOperationMode int videoMediaCodecOperationMode; private @MediaCodecRenderer.MediaCodecOperationMode int videoMediaCodecOperationMode;
private boolean enableFloatOutput;
private boolean enableOffload; private boolean enableOffload;
/** @param context A {@link Context}. */ /** @param context A {@link Context}. */
@ -218,6 +220,22 @@ public class DefaultRenderersFactory implements RenderersFactory {
return this; return this;
} }
/**
* Sets whether floating point audio should be output when possible.
*
* <p>Enabling floating point output disables audio processing, but may allow for higher quality
* audio output.
*
* <p>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. * Sets whether audio should be played using the offload path.
* *
@ -272,16 +290,18 @@ public class DefaultRenderersFactory implements RenderersFactory {
videoRendererEventListener, videoRendererEventListener,
allowedVideoJoiningTimeMs, allowedVideoJoiningTimeMs,
renderersList); renderersList);
@Nullable AudioSink audioSink = buildAudioSink(context, enableFloatOutput, enableOffload);
if (audioSink != null) {
buildAudioRenderers( buildAudioRenderers(
context, context,
extensionRendererMode, extensionRendererMode,
mediaCodecSelector, mediaCodecSelector,
enableDecoderFallback, enableDecoderFallback,
buildAudioProcessors(), audioSink,
eventHandler, eventHandler,
audioRendererEventListener, audioRendererEventListener,
enableOffload,
renderersList); renderersList);
}
buildTextRenderers(context, textRendererOutput, eventHandler.getLooper(), buildTextRenderers(context, textRendererOutput, eventHandler.getLooper(),
extensionRendererMode, renderersList); extensionRendererMode, renderersList);
buildMetadataRenderers(context, metadataRendererOutput, eventHandler.getLooper(), 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 * @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 * initialization fails. This may result in using a decoder that is slower/less efficient than
* the primary decoder. * the primary decoder.
* @param audioProcessors An array of {@link AudioProcessor}s that will process PCM audio buffers * @param audioSink A sink to which the renderers will output.
* before output. May be empty.
* @param eventHandler A handler to use when invoking event listeners and outputs. * @param eventHandler A handler to use when invoking event listeners and outputs.
* @param eventListener An event listener. * @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. * @param out An array to which the built renderers should be appended.
*/ */
protected void buildAudioRenderers( protected void buildAudioRenderers(
@ -440,10 +457,9 @@ public class DefaultRenderersFactory implements RenderersFactory {
@ExtensionRendererMode int extensionRendererMode, @ExtensionRendererMode int extensionRendererMode,
MediaCodecSelector mediaCodecSelector, MediaCodecSelector mediaCodecSelector,
boolean enableDecoderFallback, boolean enableDecoderFallback,
AudioProcessor[] audioProcessors, AudioSink audioSink,
Handler eventHandler, Handler eventHandler,
AudioRendererEventListener eventListener, AudioRendererEventListener eventListener,
boolean enableOffload,
ArrayList<Renderer> out) { ArrayList<Renderer> out) {
MediaCodecAudioRenderer audioRenderer = MediaCodecAudioRenderer audioRenderer =
new MediaCodecAudioRenderer( new MediaCodecAudioRenderer(
@ -452,11 +468,7 @@ public class DefaultRenderersFactory implements RenderersFactory {
enableDecoderFallback, enableDecoderFallback,
eventHandler, eventHandler,
eventListener, eventListener,
new DefaultAudioSink( audioSink);
AudioCapabilities.getCapabilities(context),
new DefaultAudioProcessorChain(audioProcessors),
/* enableFloatOutput= */ false,
enableOffload));
audioRenderer.experimental_setMediaCodecOperationMode(audioMediaCodecOperationMode); audioRenderer.experimental_setMediaCodecOperationMode(audioMediaCodecOperationMode);
out.add(audioRenderer); out.add(audioRenderer);
@ -476,10 +488,10 @@ public class DefaultRenderersFactory implements RenderersFactory {
clazz.getConstructor( clazz.getConstructor(
android.os.Handler.class, android.os.Handler.class,
com.google.android.exoplayer2.audio.AudioRendererEventListener.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) // LINT.ThenChange(../../../../../../../proguard-rules.txt)
Renderer renderer = Renderer renderer =
(Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors); (Renderer) constructor.newInstance(eventHandler, eventListener, audioSink);
out.add(extensionRendererIndex++, renderer); out.add(extensionRendererIndex++, renderer);
Log.i(TAG, "Loaded LibopusAudioRenderer."); Log.i(TAG, "Loaded LibopusAudioRenderer.");
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
@ -497,10 +509,10 @@ public class DefaultRenderersFactory implements RenderersFactory {
clazz.getConstructor( clazz.getConstructor(
android.os.Handler.class, android.os.Handler.class,
com.google.android.exoplayer2.audio.AudioRendererEventListener.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) // LINT.ThenChange(../../../../../../../proguard-rules.txt)
Renderer renderer = Renderer renderer =
(Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors); (Renderer) constructor.newInstance(eventHandler, eventListener, audioSink);
out.add(extensionRendererIndex++, renderer); out.add(extensionRendererIndex++, renderer);
Log.i(TAG, "Loaded LibflacAudioRenderer."); Log.i(TAG, "Loaded LibflacAudioRenderer.");
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
@ -519,10 +531,10 @@ public class DefaultRenderersFactory implements RenderersFactory {
clazz.getConstructor( clazz.getConstructor(
android.os.Handler.class, android.os.Handler.class,
com.google.android.exoplayer2.audio.AudioRendererEventListener.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) // LINT.ThenChange(../../../../../../../proguard-rules.txt)
Renderer renderer = Renderer renderer =
(Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors); (Renderer) constructor.newInstance(eventHandler, eventListener, audioSink);
out.add(extensionRendererIndex++, renderer); out.add(extensionRendererIndex++, renderer);
Log.i(TAG, "Loaded FfmpegAudioRenderer."); Log.i(TAG, "Loaded FfmpegAudioRenderer.");
} catch (ClassNotFoundException e) { } 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() { @Nullable
return new AudioProcessor[0]; protected AudioSink buildAudioSink(
Context context, boolean enableFloatOutput, boolean enableOffload) {
return new DefaultAudioSink(
AudioCapabilities.getCapabilities(context),
new DefaultAudioProcessorChain(),
enableFloatOutput,
enableOffload);
} }
} }

View File

@ -365,14 +365,15 @@ public final class DefaultAudioSink implements AudioSink {
* parameters adjustments. The instance passed in must not be reused in other sinks. * 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 * @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 * 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 * (24-bit or 32-bit) integer PCM. Float output is supported from API level 21. Audio
* be available when float output is in use. * processing (for example, speed adjustment) will not be available when float output is in
* @param enableOffload Whether audio offloading is enabled. If an audio format can be both played * 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 * 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 * supported from API level 29. Most Android devices can only support one offload {@link
* devices can only support one offload {@link android.media.AudioTrack} at a time and can * android.media.AudioTrack} at a time and can invalidate it at any time. Thus an app can
* invalidate it at any time. Thus an app can never be guaranteed that it will be able to play * never be guaranteed that it will be able to play in offload. Audio processing (for example,
* in offload. * speed adjustment) will not be available when offload is in use.
*/ */
public DefaultAudioSink( public DefaultAudioSink(
@Nullable AudioCapabilities audioCapabilities, @Nullable AudioCapabilities audioCapabilities,