Force AudioTrack-based speed changes when offload is enabled

AudioProcessor-based speed changes are not supported with
offload, so we should use the AudioTrack-based speed changes
by default if the user requests a speed change.

This moves the decision of which speed change path is used
into the Configuration, so that it can change for each
AudioTrack in a playlist.

PiperOrigin-RevId: 505621911
This commit is contained in:
tonihei 2023-01-30 09:39:27 +00:00 committed by christosts
parent d7ef1ab5bd
commit 0d4e29ffc4

View File

@ -476,7 +476,7 @@ public final class DefaultAudioSink implements AudioSink {
private final ConditionVariable releasingConditionVariable; private final ConditionVariable releasingConditionVariable;
private final AudioTrackPositionTracker audioTrackPositionTracker; private final AudioTrackPositionTracker audioTrackPositionTracker;
private final ArrayDeque<MediaPositionParameters> mediaPositionParametersCheckpoints; private final ArrayDeque<MediaPositionParameters> mediaPositionParametersCheckpoints;
private final boolean enableAudioTrackPlaybackParams; private final boolean preferAudioTrackPlaybackParams;
private final @OffloadMode int offloadMode; private final @OffloadMode int offloadMode;
private @MonotonicNonNull StreamEventCallbackV29 offloadStreamEventCallbackV29; private @MonotonicNonNull StreamEventCallbackV29 offloadStreamEventCallbackV29;
private final PendingExceptionHolder<InitializationException> private final PendingExceptionHolder<InitializationException>
@ -535,7 +535,7 @@ public final class DefaultAudioSink implements AudioSink {
audioCapabilities = builder.audioCapabilities; audioCapabilities = builder.audioCapabilities;
audioProcessorChain = builder.audioProcessorChain; audioProcessorChain = builder.audioProcessorChain;
enableFloatOutput = Util.SDK_INT >= 21 && builder.enableFloatOutput; enableFloatOutput = Util.SDK_INT >= 21 && builder.enableFloatOutput;
enableAudioTrackPlaybackParams = Util.SDK_INT >= 23 && builder.enableAudioTrackPlaybackParams; preferAudioTrackPlaybackParams = Util.SDK_INT >= 23 && builder.enableAudioTrackPlaybackParams;
offloadMode = Util.SDK_INT >= 29 ? builder.offloadMode : OFFLOAD_MODE_DISABLED; offloadMode = Util.SDK_INT >= 29 ? builder.offloadMode : OFFLOAD_MODE_DISABLED;
audioTrackBufferSizeProvider = builder.audioTrackBufferSizeProvider; audioTrackBufferSizeProvider = builder.audioTrackBufferSizeProvider;
releasingConditionVariable = new ConditionVariable(Clock.DEFAULT); releasingConditionVariable = new ConditionVariable(Clock.DEFAULT);
@ -625,6 +625,7 @@ public final class DefaultAudioSink implements AudioSink {
int outputSampleRate; int outputSampleRate;
int outputChannelConfig; int outputChannelConfig;
int outputPcmFrameSize; int outputPcmFrameSize;
boolean enableAudioTrackPlaybackParams;
if (MimeTypes.AUDIO_RAW.equals(inputFormat.sampleMimeType)) { if (MimeTypes.AUDIO_RAW.equals(inputFormat.sampleMimeType)) {
Assertions.checkArgument(Util.isEncodingLinearPcm(inputFormat.pcmEncoding)); Assertions.checkArgument(Util.isEncodingLinearPcm(inputFormat.pcmEncoding));
@ -673,6 +674,7 @@ public final class DefaultAudioSink implements AudioSink {
outputSampleRate = outputFormat.sampleRate; outputSampleRate = outputFormat.sampleRate;
outputChannelConfig = Util.getAudioTrackChannelConfig(outputFormat.channelCount); outputChannelConfig = Util.getAudioTrackChannelConfig(outputFormat.channelCount);
outputPcmFrameSize = Util.getPcmFrameSize(outputEncoding, outputFormat.channelCount); outputPcmFrameSize = Util.getPcmFrameSize(outputEncoding, outputFormat.channelCount);
enableAudioTrackPlaybackParams = preferAudioTrackPlaybackParams;
} else { } else {
// Audio processing is not supported in offload or passthrough mode. // Audio processing is not supported in offload or passthrough mode.
audioProcessingPipeline = new AudioProcessingPipeline(ImmutableList.of()); audioProcessingPipeline = new AudioProcessingPipeline(ImmutableList.of());
@ -684,6 +686,8 @@ public final class DefaultAudioSink implements AudioSink {
outputEncoding = outputEncoding =
MimeTypes.getEncoding(checkNotNull(inputFormat.sampleMimeType), inputFormat.codecs); MimeTypes.getEncoding(checkNotNull(inputFormat.sampleMimeType), inputFormat.codecs);
outputChannelConfig = Util.getAudioTrackChannelConfig(inputFormat.channelCount); outputChannelConfig = Util.getAudioTrackChannelConfig(inputFormat.channelCount);
// Offload requires AudioTrack playback parameters to apply speed changes quickly.
enableAudioTrackPlaybackParams = true;
} else { } else {
outputMode = OUTPUT_MODE_PASSTHROUGH; outputMode = OUTPUT_MODE_PASSTHROUGH;
@Nullable @Nullable
@ -695,6 +699,9 @@ public final class DefaultAudioSink implements AudioSink {
} }
outputEncoding = encodingAndChannelConfig.first; outputEncoding = encodingAndChannelConfig.first;
outputChannelConfig = encodingAndChannelConfig.second; outputChannelConfig = encodingAndChannelConfig.second;
// Passthrough only supports AudioTrack playback parameters, but we only enable it this was
// specifically requested by the app.
enableAudioTrackPlaybackParams = preferAudioTrackPlaybackParams;
} }
} }
@ -730,7 +737,8 @@ public final class DefaultAudioSink implements AudioSink {
outputChannelConfig, outputChannelConfig,
outputEncoding, outputEncoding,
bufferSize, bufferSize,
audioProcessingPipeline); audioProcessingPipeline,
enableAudioTrackPlaybackParams);
if (isAudioTrackInitialized()) { if (isAudioTrackInitialized()) {
this.pendingConfiguration = pendingConfiguration; this.pendingConfiguration = pendingConfiguration;
} else { } else {
@ -1525,12 +1533,14 @@ public final class DefaultAudioSink implements AudioSink {
// would require decoding/re-encoding; and // would require decoding/re-encoding; and
// - when outputting float PCM audio, because SonicAudioProcessor outputs 16-bit integer PCM. // - when outputting float PCM audio, because SonicAudioProcessor outputs 16-bit integer PCM.
return !tunneling return !tunneling
&& MimeTypes.AUDIO_RAW.equals(configuration.inputFormat.sampleMimeType) && configuration.outputMode == OUTPUT_MODE_PCM
&& !shouldUseFloatOutput(configuration.inputFormat.pcmEncoding); && !shouldUseFloatOutput(configuration.inputFormat.pcmEncoding);
} }
private boolean useAudioTrackPlaybackParams() { private boolean useAudioTrackPlaybackParams() {
return configuration != null && enableAudioTrackPlaybackParams && Util.SDK_INT >= 23; return configuration != null
&& configuration.enableAudioTrackPlaybackParams
&& Util.SDK_INT >= 23;
} }
/** /**
@ -1968,6 +1978,7 @@ public final class DefaultAudioSink implements AudioSink {
public final @C.Encoding int outputEncoding; public final @C.Encoding int outputEncoding;
public final int bufferSize; public final int bufferSize;
public final AudioProcessingPipeline audioProcessingPipeline; public final AudioProcessingPipeline audioProcessingPipeline;
public final boolean enableAudioTrackPlaybackParams;
public Configuration( public Configuration(
Format inputFormat, Format inputFormat,
@ -1978,7 +1989,8 @@ public final class DefaultAudioSink implements AudioSink {
int outputChannelConfig, int outputChannelConfig,
int outputEncoding, int outputEncoding,
int bufferSize, int bufferSize,
AudioProcessingPipeline audioProcessingPipeline) { AudioProcessingPipeline audioProcessingPipeline,
boolean enableAudioTrackPlaybackParams) {
this.inputFormat = inputFormat; this.inputFormat = inputFormat;
this.inputPcmFrameSize = inputPcmFrameSize; this.inputPcmFrameSize = inputPcmFrameSize;
this.outputMode = outputMode; this.outputMode = outputMode;
@ -1988,6 +2000,7 @@ public final class DefaultAudioSink implements AudioSink {
this.outputEncoding = outputEncoding; this.outputEncoding = outputEncoding;
this.bufferSize = bufferSize; this.bufferSize = bufferSize;
this.audioProcessingPipeline = audioProcessingPipeline; this.audioProcessingPipeline = audioProcessingPipeline;
this.enableAudioTrackPlaybackParams = enableAudioTrackPlaybackParams;
} }
public Configuration copyWithBufferSize(int bufferSize) { public Configuration copyWithBufferSize(int bufferSize) {
@ -2000,16 +2013,18 @@ public final class DefaultAudioSink implements AudioSink {
outputChannelConfig, outputChannelConfig,
outputEncoding, outputEncoding,
bufferSize, bufferSize,
audioProcessingPipeline); audioProcessingPipeline,
enableAudioTrackPlaybackParams);
} }
/** Returns if the configurations are sufficiently compatible to reuse the audio track. */ /** Returns if the configurations are sufficiently compatible to reuse the audio track. */
public boolean canReuseAudioTrack(Configuration audioTrackConfiguration) { public boolean canReuseAudioTrack(Configuration newConfiguration) {
return audioTrackConfiguration.outputMode == outputMode return newConfiguration.outputMode == outputMode
&& audioTrackConfiguration.outputEncoding == outputEncoding && newConfiguration.outputEncoding == outputEncoding
&& audioTrackConfiguration.outputSampleRate == outputSampleRate && newConfiguration.outputSampleRate == outputSampleRate
&& audioTrackConfiguration.outputChannelConfig == outputChannelConfig && newConfiguration.outputChannelConfig == outputChannelConfig
&& audioTrackConfiguration.outputPcmFrameSize == outputPcmFrameSize; && newConfiguration.outputPcmFrameSize == outputPcmFrameSize
&& newConfiguration.enableAudioTrackPlaybackParams == enableAudioTrackPlaybackParams;
} }
public long inputFramesToDurationUs(long frameCount) { public long inputFramesToDurationUs(long frameCount) {