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
* 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.

View File

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

View File

@ -31,15 +31,15 @@
}
-dontnote 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
-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
-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

View File

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

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.
* @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,