Scale AudioTrack buffer size for AudioTrack speed adjustment

PiperOrigin-RevId: 326642908
This commit is contained in:
andrewlewis 2020-08-14 14:20:22 +01:00 committed by kim-vde
parent eabc486b58
commit 977f0d1ed0
2 changed files with 31 additions and 30 deletions

View file

@ -191,6 +191,16 @@ public final class DefaultAudioSink implements AudioSink {
}
}
/** The default playback speed. */
public static final float DEFAULT_PLAYBACK_SPEED = 1f;
/** The minimum allowed playback speed. Lower values will be constrained to fall in range. */
public static final float MIN_PLAYBACK_SPEED = 0.1f;
/** The maximum allowed playback speed. Higher values will be constrained to fall in range. */
public static final float MAX_PLAYBACK_SPEED = 8f;
/** The default skip silence flag. */
private static final boolean DEFAULT_SKIP_SILENCE = false;
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({OUTPUT_MODE_PCM, OUTPUT_MODE_OFFLOAD, OUTPUT_MODE_PASSTHROUGH})
@ -210,11 +220,10 @@ public final class DefaultAudioSink implements AudioSink {
private static final long OFFLOAD_BUFFER_DURATION_US = 50_000_000;
/**
* A multiplication factor to apply to the minimum buffer size requested by the underlying
* {@link AudioTrack}.
* A multiplication factor to apply to the minimum buffer size requested by the underlying {@link
* AudioTrack}.
*/
private static final int BUFFER_MULTIPLICATION_FACTOR = 4;
/** To avoid underruns on some devices (e.g., Broadcom 7271), scale up the AC3 buffer duration. */
private static final int AC3_BUFFER_MULTIPLICATION_FACTOR = 2;
@ -239,10 +248,6 @@ public final class DefaultAudioSink implements AudioSink {
*/
@SuppressLint("InlinedApi")
private static final int WRITE_NON_BLOCKING = AudioTrack.WRITE_NON_BLOCKING;
/** The default playback speed. */
private static final float DEFAULT_PLAYBACK_SPEED = 1f;
/** The default skip silence flag. */
private static final boolean DEFAULT_SKIP_SILENCE = false;
private static final String TAG = "AudioTrack";
@ -582,6 +587,7 @@ public final class DefaultAudioSink implements AudioSink {
outputChannelConfig,
outputEncoding,
specifiedBufferSize,
enableAudioTrackPlaybackParams,
canApplyPlaybackParameters,
availableAudioProcessors);
if (isAudioTrackInitialized()) {
@ -1007,6 +1013,7 @@ public final class DefaultAudioSink implements AudioSink {
@Override
public void setPlaybackSpeed(float playbackSpeed) {
playbackSpeed = Util.constrainValue(playbackSpeed, MIN_PLAYBACK_SPEED, MAX_PLAYBACK_SPEED);
if (enableAudioTrackPlaybackParams && Util.SDK_INT >= 23) {
setAudioTrackPlaybackSpeedV23(playbackSpeed);
} else {
@ -1802,6 +1809,7 @@ public final class DefaultAudioSink implements AudioSink {
int outputChannelConfig,
int outputEncoding,
int specifiedBufferSize,
boolean enableAudioTrackPlaybackParams,
boolean canApplyPlaybackParameters,
AudioProcessor[] availableAudioProcessors) {
this.inputFormat = inputFormat;
@ -1815,7 +1823,7 @@ public final class DefaultAudioSink implements AudioSink {
this.availableAudioProcessors = availableAudioProcessors;
// Call computeBufferSize() last as it depends on the other configuration values.
this.bufferSize = computeBufferSize(specifiedBufferSize);
this.bufferSize = computeBufferSize(specifiedBufferSize, enableAudioTrackPlaybackParams);
}
/** Returns if the configurations are sufficiently compatible to reuse the audio track. */
@ -1925,13 +1933,15 @@ public final class DefaultAudioSink implements AudioSink {
}
}
private int computeBufferSize(int specifiedBufferSize) {
private int computeBufferSize(
int specifiedBufferSize, boolean enableAudioTrackPlaybackParameters) {
if (specifiedBufferSize != 0) {
return specifiedBufferSize;
}
switch (outputMode) {
case OUTPUT_MODE_PCM:
return getPcmDefaultBufferSize();
return getPcmDefaultBufferSize(
enableAudioTrackPlaybackParameters ? MAX_PLAYBACK_SPEED : DEFAULT_PLAYBACK_SPEED);
case OUTPUT_MODE_OFFLOAD:
return getEncodedDefaultBufferSize(OFFLOAD_BUFFER_DURATION_US);
case OUTPUT_MODE_PASSTHROUGH:
@ -1949,7 +1959,7 @@ public final class DefaultAudioSink implements AudioSink {
return (int) (bufferDurationUs * rate / C.MICROS_PER_SECOND);
}
private int getPcmDefaultBufferSize() {
private int getPcmDefaultBufferSize(float maxAudioTrackPlaybackSpeed) {
int minBufferSize =
AudioTrack.getMinBufferSize(outputSampleRate, outputChannelConfig, outputEncoding);
Assertions.checkState(minBufferSize != ERROR_BAD_VALUE);
@ -1957,7 +1967,13 @@ public final class DefaultAudioSink implements AudioSink {
int minAppBufferSize = (int) durationUsToFrames(MIN_BUFFER_DURATION_US) * outputPcmFrameSize;
int maxAppBufferSize =
max(minBufferSize, (int) durationUsToFrames(MAX_BUFFER_DURATION_US) * outputPcmFrameSize);
return Util.constrainValue(multipliedBufferSize, minAppBufferSize, maxAppBufferSize);
int bufferSize =
Util.constrainValue(multipliedBufferSize, minAppBufferSize, maxAppBufferSize);
if (maxAudioTrackPlaybackSpeed != 1f) {
// Maintain the buffer duration by scaling the size accordingly.
bufferSize = Math.round(bufferSize * maxAudioTrackPlaybackSpeed);
}
return bufferSize;
}
@RequiresApi(21)

View file

@ -29,22 +29,10 @@ import java.nio.ShortBuffer;
*/
public final class SonicAudioProcessor implements AudioProcessor {
/**
* The maximum allowed playback speed in {@link #setSpeed(float)}.
*/
public static final float MAXIMUM_SPEED = 8.0f;
/**
* The minimum allowed playback speed in {@link #setSpeed(float)}.
*/
public static final float MINIMUM_SPEED = 0.1f;
/**
* Indicates that the output sample rate should be the same as the input.
*/
/** Indicates that the output sample rate should be the same as the input. */
public static final int SAMPLE_RATE_NO_CHANGE = -1;
/**
* The threshold below which the difference between two pitch/speed factors is negligible.
*/
/** The threshold below which the difference between two pitch/speed factors is negligible. */
private static final float CLOSE_THRESHOLD = 0.01f;
/**
@ -70,9 +58,7 @@ public final class SonicAudioProcessor implements AudioProcessor {
private long outputBytes;
private boolean inputEnded;
/**
* Creates a new Sonic audio processor.
*/
/** Creates a new Sonic audio processor. */
public SonicAudioProcessor() {
speed = 1f;
pendingInputAudioFormat = AudioFormat.NOT_SET;
@ -94,7 +80,6 @@ public final class SonicAudioProcessor implements AudioProcessor {
* @return The actual new playback speed.
*/
public float setSpeed(float speed) {
speed = Util.constrainValue(speed, MINIMUM_SPEED, MAXIMUM_SPEED);
if (this.speed != speed) {
this.speed = speed;
pendingSonicRecreation = true;