mirror of
https://github.com/androidx/media.git
synced 2025-05-15 19:49:50 +08:00
Make flush() update parameters, and make Sonic flushable
Previously it was necessary to create a new Sonic instance every time the processor was flushed. Add a flush() method to Sonic so that it can be reused when seeking. It still needs to be recreated when parameters change. SonicAudioProcessor and SilenceSkippingAudioProcessor have methods for setting parameters that are documented as taking effect after a call to flush(), but actually the value returned by isActive() was updated immediately. Track the pending values and apply them in flush() to fix this. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=191442336
This commit is contained in:
parent
cb01b281df
commit
f2399c1c85
@ -29,6 +29,9 @@ import java.nio.ByteOrder;
|
||||
* {@link #getOutputChannelCount()}, {@link #getOutputEncoding()} and {@link
|
||||
* #getOutputSampleRateHz()} may only be called if the processor is active. Call {@link #reset()} to
|
||||
* reset the processor to its unconfigured state and release any resources.
|
||||
*
|
||||
* <p>In addition to being able to modify the format of audio, implementations may allow parameters
|
||||
* to be set that affect the output audio and whether the processor is active/inactive.
|
||||
*/
|
||||
public interface AudioProcessor {
|
||||
|
||||
@ -47,10 +50,9 @@ public interface AudioProcessor {
|
||||
|
||||
/**
|
||||
* Configures the processor to process input audio with the specified format and returns whether
|
||||
* to {@link #flush()} it. After calling this method, {@link #isActive()} returns whether the
|
||||
* processor needs to handle buffers; if not, the processor will not accept any buffers until it
|
||||
* is reconfigured. If the processor is active, {@link #getOutputSampleRateHz()}, {@link
|
||||
* #getOutputChannelCount()} and {@link #getOutputEncoding()} return its output format.
|
||||
* to {@link #flush()} it. After calling this method, if the processor is active, {@link
|
||||
* #getOutputSampleRateHz()}, {@link #getOutputChannelCount()} and {@link #getOutputEncoding()}
|
||||
* return its output format.
|
||||
*
|
||||
* @param sampleRateHz The sample rate of input audio in Hz.
|
||||
* @param channelCount The number of interleaved channels in input audio.
|
||||
@ -61,7 +63,7 @@ public interface AudioProcessor {
|
||||
boolean configure(int sampleRateHz, int channelCount, @C.Encoding int encoding)
|
||||
throws UnhandledFormatException;
|
||||
|
||||
/** Returns whether the processor is configured and active. */
|
||||
/** Returns whether the processor is configured and will process input buffers. */
|
||||
boolean isActive();
|
||||
|
||||
/**
|
||||
|
@ -531,8 +531,12 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
drainingPlaybackParameters, Math.max(0, presentationTimeUs),
|
||||
framesToDurationUs(getWrittenFrames())));
|
||||
drainingPlaybackParameters = null;
|
||||
// The audio processors have drained, so flush them. This will cause any active speed
|
||||
// adjustment audio processor to start producing audio with the new parameters.
|
||||
|
||||
// Flush the audio processors so that any new parameters take effect.
|
||||
// TODO: Move parameter setting from setPlaybackParameters to here, so that it's not
|
||||
// necessary to flush the processors twice.
|
||||
sonicAudioProcessor.flush();
|
||||
silenceSkippingAudioProcessor.flush();
|
||||
setupAudioProcessors();
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,7 @@ import java.nio.ByteOrder;
|
||||
private int bytesPerFrame;
|
||||
|
||||
private boolean enabled;
|
||||
private boolean pendingEnabled;
|
||||
|
||||
private ByteBuffer buffer;
|
||||
private ByteBuffer outputBuffer;
|
||||
@ -113,7 +114,7 @@ import java.nio.ByteOrder;
|
||||
* @param enabled Whether to skip silence in the input.
|
||||
*/
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
pendingEnabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -207,6 +208,7 @@ import java.nio.ByteOrder;
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
enabled = pendingEnabled;
|
||||
if (isActive()) {
|
||||
int maybeSilenceBufferSize = durationUsToFrames(MINIMUM_SILENCE_DURATION_US) * bytesPerFrame;
|
||||
if (maybeSilenceBuffer.length != maybeSilenceBufferSize) {
|
||||
@ -228,6 +230,7 @@ import java.nio.ByteOrder;
|
||||
@Override
|
||||
public void reset() {
|
||||
enabled = false;
|
||||
pendingEnabled = false;
|
||||
flush();
|
||||
buffer = EMPTY_BUFFER;
|
||||
channelCount = Format.NO_VALUE;
|
||||
|
@ -143,6 +143,20 @@ import java.util.Arrays;
|
||||
pitchFrameCount = 0;
|
||||
}
|
||||
|
||||
/** Clears state in preparation for receiving a new stream of input buffers. */
|
||||
public void flush() {
|
||||
inputFrameCount = 0;
|
||||
outputFrameCount = 0;
|
||||
pitchFrameCount = 0;
|
||||
oldRatePosition = 0;
|
||||
newRatePosition = 0;
|
||||
remainingInputToCopyFrameCount = 0;
|
||||
prevPeriod = 0;
|
||||
prevMinDiff = 0;
|
||||
minDiff = 0;
|
||||
maxDiff = 0;
|
||||
}
|
||||
|
||||
/** Returns the number of output frames that can be read with {@link #getOutput(ShortBuffer)}. */
|
||||
public int getFramesAvailable() {
|
||||
return outputFrameCount;
|
||||
|
@ -62,15 +62,16 @@ public final class SonicAudioProcessor implements AudioProcessor {
|
||||
*/
|
||||
private static final int MIN_BYTES_FOR_SPEEDUP_CALCULATION = 1024;
|
||||
|
||||
private int pendingOutputSampleRateHz;
|
||||
private int channelCount;
|
||||
private int sampleRateHz;
|
||||
|
||||
private @Nullable Sonic sonic;
|
||||
private float speed;
|
||||
private float pitch;
|
||||
private int outputSampleRateHz;
|
||||
private float pendingSpeed;
|
||||
private float pendingPitch;
|
||||
private int pendingOutputSampleRateHz;
|
||||
|
||||
private @Nullable Sonic sonic;
|
||||
private ByteBuffer buffer;
|
||||
private ShortBuffer shortBuffer;
|
||||
private ByteBuffer outputBuffer;
|
||||
@ -84,6 +85,8 @@ public final class SonicAudioProcessor implements AudioProcessor {
|
||||
public SonicAudioProcessor() {
|
||||
speed = 1f;
|
||||
pitch = 1f;
|
||||
pendingSpeed = 1f;
|
||||
pendingPitch = 1f;
|
||||
channelCount = Format.NO_VALUE;
|
||||
sampleRateHz = Format.NO_VALUE;
|
||||
outputSampleRateHz = Format.NO_VALUE;
|
||||
@ -100,8 +103,8 @@ public final class SonicAudioProcessor implements AudioProcessor {
|
||||
* @return The actual new playback speed.
|
||||
*/
|
||||
public float setSpeed(float speed) {
|
||||
this.speed = Util.constrainValue(speed, MINIMUM_SPEED, MAXIMUM_SPEED);
|
||||
return this.speed;
|
||||
pendingSpeed = Util.constrainValue(speed, MINIMUM_SPEED, MAXIMUM_SPEED);
|
||||
return pendingSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -111,8 +114,8 @@ public final class SonicAudioProcessor implements AudioProcessor {
|
||||
* @return The actual new pitch.
|
||||
*/
|
||||
public float setPitch(float pitch) {
|
||||
this.pitch = Util.constrainValue(pitch, MINIMUM_PITCH, MAXIMUM_PITCH);
|
||||
return pitch;
|
||||
pendingPitch = Util.constrainValue(pitch, MINIMUM_PITCH, MAXIMUM_PITCH);
|
||||
return pendingPitch;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -161,6 +164,7 @@ public final class SonicAudioProcessor implements AudioProcessor {
|
||||
this.sampleRateHz = sampleRateHz;
|
||||
this.channelCount = channelCount;
|
||||
this.outputSampleRateHz = outputSampleRateHz;
|
||||
sonic = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -232,8 +236,16 @@ public final class SonicAudioProcessor implements AudioProcessor {
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
sonic =
|
||||
isActive() ? new Sonic(sampleRateHz, channelCount, speed, pitch, outputSampleRateHz) : null;
|
||||
boolean parametersChanged = pendingSpeed != speed || pendingPitch != pitch;
|
||||
speed = pendingSpeed;
|
||||
pitch = pendingPitch;
|
||||
if (isActive()) {
|
||||
if (sonic == null || parametersChanged) {
|
||||
sonic = new Sonic(sampleRateHz, channelCount, speed, pitch, outputSampleRateHz);
|
||||
} else {
|
||||
sonic.flush();
|
||||
}
|
||||
}
|
||||
outputBuffer = EMPTY_BUFFER;
|
||||
inputBytes = 0;
|
||||
outputBytes = 0;
|
||||
@ -244,6 +256,8 @@ public final class SonicAudioProcessor implements AudioProcessor {
|
||||
public void reset() {
|
||||
speed = 1f;
|
||||
pitch = 1f;
|
||||
pendingSpeed = 1f;
|
||||
pendingPitch = 1f;
|
||||
channelCount = Format.NO_VALUE;
|
||||
sampleRateHz = Format.NO_VALUE;
|
||||
outputSampleRateHz = Format.NO_VALUE;
|
||||
|
@ -56,6 +56,7 @@ public final class SilenceSkippingAudioProcessorTest {
|
||||
boolean reconfigured =
|
||||
silenceSkippingAudioProcessor.configure(
|
||||
TEST_SIGNAL_SAMPLE_RATE_HZ, TEST_SIGNAL_CHANNEL_COUNT, C.ENCODING_PCM_16BIT);
|
||||
silenceSkippingAudioProcessor.flush();
|
||||
|
||||
// It's active.
|
||||
assertThat(reconfigured).isTrue();
|
||||
@ -115,6 +116,7 @@ public final class SilenceSkippingAudioProcessorTest {
|
||||
silenceSkippingAudioProcessor.configure(
|
||||
TEST_SIGNAL_SAMPLE_RATE_HZ, TEST_SIGNAL_CHANNEL_COUNT, C.ENCODING_PCM_16BIT);
|
||||
assertThat(reconfigured).isTrue();
|
||||
silenceSkippingAudioProcessor.flush();
|
||||
|
||||
// When reconfiguring it with the same sample rate.
|
||||
reconfigured =
|
||||
@ -142,6 +144,7 @@ public final class SilenceSkippingAudioProcessorTest {
|
||||
boolean reconfigured =
|
||||
silenceSkippingAudioProcessor.configure(
|
||||
TEST_SIGNAL_SAMPLE_RATE_HZ, TEST_SIGNAL_CHANNEL_COUNT, C.ENCODING_PCM_16BIT);
|
||||
silenceSkippingAudioProcessor.flush();
|
||||
assertThat(reconfigured).isTrue();
|
||||
assertThat(silenceSkippingAudioProcessor.isActive()).isTrue();
|
||||
long totalOutputFrames =
|
||||
@ -170,6 +173,7 @@ public final class SilenceSkippingAudioProcessorTest {
|
||||
boolean reconfigured =
|
||||
silenceSkippingAudioProcessor.configure(
|
||||
TEST_SIGNAL_SAMPLE_RATE_HZ, TEST_SIGNAL_CHANNEL_COUNT, C.ENCODING_PCM_16BIT);
|
||||
silenceSkippingAudioProcessor.flush();
|
||||
assertThat(reconfigured).isTrue();
|
||||
assertThat(silenceSkippingAudioProcessor.isActive()).isTrue();
|
||||
long totalOutputFrames =
|
||||
@ -199,6 +203,7 @@ public final class SilenceSkippingAudioProcessorTest {
|
||||
boolean reconfigured =
|
||||
silenceSkippingAudioProcessor.configure(
|
||||
TEST_SIGNAL_SAMPLE_RATE_HZ, TEST_SIGNAL_CHANNEL_COUNT, C.ENCODING_PCM_16BIT);
|
||||
silenceSkippingAudioProcessor.flush();
|
||||
assertThat(reconfigured).isTrue();
|
||||
assertThat(silenceSkippingAudioProcessor.isActive()).isTrue();
|
||||
long totalOutputFrames =
|
||||
@ -228,6 +233,7 @@ public final class SilenceSkippingAudioProcessorTest {
|
||||
boolean reconfigured =
|
||||
silenceSkippingAudioProcessor.configure(
|
||||
TEST_SIGNAL_SAMPLE_RATE_HZ, TEST_SIGNAL_CHANNEL_COUNT, C.ENCODING_PCM_16BIT);
|
||||
silenceSkippingAudioProcessor.flush();
|
||||
assertThat(reconfigured).isTrue();
|
||||
assertThat(silenceSkippingAudioProcessor.isActive()).isTrue();
|
||||
long totalOutputFrames =
|
||||
@ -257,6 +263,7 @@ public final class SilenceSkippingAudioProcessorTest {
|
||||
boolean reconfigured =
|
||||
silenceSkippingAudioProcessor.configure(
|
||||
TEST_SIGNAL_SAMPLE_RATE_HZ, TEST_SIGNAL_CHANNEL_COUNT, C.ENCODING_PCM_16BIT);
|
||||
silenceSkippingAudioProcessor.flush();
|
||||
assertThat(reconfigured).isTrue();
|
||||
assertThat(silenceSkippingAudioProcessor.isActive()).isTrue();
|
||||
long totalOutputFrames =
|
||||
@ -285,6 +292,7 @@ public final class SilenceSkippingAudioProcessorTest {
|
||||
boolean reconfigured =
|
||||
silenceSkippingAudioProcessor.configure(
|
||||
TEST_SIGNAL_SAMPLE_RATE_HZ, TEST_SIGNAL_CHANNEL_COUNT, C.ENCODING_PCM_16BIT);
|
||||
silenceSkippingAudioProcessor.flush();
|
||||
assertThat(reconfigured).isTrue();
|
||||
assertThat(silenceSkippingAudioProcessor.isActive()).isTrue();
|
||||
process(silenceSkippingAudioProcessor, inputBufferProvider, INPUT_BUFFER_SIZE);
|
||||
|
@ -94,6 +94,7 @@ public final class SonicAudioProcessorTest {
|
||||
public void testIsActiveWithSpeedChange() throws Exception {
|
||||
sonicAudioProcessor.setSpeed(1.5f);
|
||||
sonicAudioProcessor.configure(44100, 2, C.ENCODING_PCM_16BIT);
|
||||
sonicAudioProcessor.flush();
|
||||
assertThat(sonicAudioProcessor.isActive()).isTrue();
|
||||
}
|
||||
|
||||
@ -101,6 +102,7 @@ public final class SonicAudioProcessorTest {
|
||||
public void testIsActiveWithPitchChange() throws Exception {
|
||||
sonicAudioProcessor.setPitch(1.5f);
|
||||
sonicAudioProcessor.configure(44100, 2, C.ENCODING_PCM_16BIT);
|
||||
sonicAudioProcessor.flush();
|
||||
assertThat(sonicAudioProcessor.isActive()).isTrue();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user