PiperOrigin-RevId: 702943864
This commit is contained in:
Googler 2024-12-04 19:19:39 -08:00 committed by Copybara-Service
parent 6193f7c38f
commit f60d2b4146
2 changed files with 21 additions and 61 deletions

View file

@ -24,6 +24,7 @@ import static androidx.media3.common.util.Util.sampleCountToDurationUs;
import static java.lang.Math.min; import static java.lang.Math.min;
import static java.lang.Math.round; import static java.lang.Math.round;
import android.annotation.SuppressLint;
import androidx.annotation.GuardedBy; import androidx.annotation.GuardedBy;
import androidx.annotation.IntRange; import androidx.annotation.IntRange;
import androidx.media3.common.C; import androidx.media3.common.C;
@ -44,8 +45,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** /**
* An {@link AudioProcessor} that changes the speed of audio samples depending on their timestamp. * An {@link AudioProcessor} that changes the speed of audio samples depending on their timestamp.
*/ */
// TODO(b/288221200): Consider making the processor inactive and skipping it in the processor chain
// when speed is 1.
@UnstableApi @UnstableApi
public final class SpeedChangingAudioProcessor implements AudioProcessor { public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
private final Object lock; private final Object lock;
@ -94,18 +97,7 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
private boolean endOfStreamQueuedToSonic; private boolean endOfStreamQueuedToSonic;
/** The current input audio format. */
private AudioFormat inputAudioFormat;
private AudioFormat pendingInputAudioFormat;
private AudioFormat pendingOutputAudioFormat;
private boolean inputEnded;
public SpeedChangingAudioProcessor(SpeedProvider speedProvider) { public SpeedChangingAudioProcessor(SpeedProvider speedProvider) {
pendingInputAudioFormat = AudioFormat.NOT_SET;
pendingOutputAudioFormat = AudioFormat.NOT_SET;
inputAudioFormat = AudioFormat.NOT_SET;
this.speedProvider = speedProvider; this.speedProvider = speedProvider;
lock = new Object(); lock = new Object();
sonicAudioProcessor = sonicAudioProcessor =
@ -113,7 +105,7 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
pendingCallbackInputTimesUs = new LongArrayQueue(); pendingCallbackInputTimesUs = new LongArrayQueue();
pendingCallbacks = new ArrayDeque<>(); pendingCallbacks = new ArrayDeque<>();
speedAdjustedTimeAsyncInputTimeUs = C.TIME_UNSET; speedAdjustedTimeAsyncInputTimeUs = C.TIME_UNSET;
resetInternalState(); resetState();
} }
/** Returns the estimated number of samples output given the provided parameters. */ /** Returns the estimated number of samples output given the provided parameters. */
@ -152,23 +144,17 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
return outputSamples; return outputSamples;
} }
@Override
public AudioFormat configure(AudioFormat inputAudioFormat) throws UnhandledAudioFormatException {
pendingInputAudioFormat = inputAudioFormat;
pendingOutputAudioFormat = sonicAudioProcessor.configure(inputAudioFormat);
return pendingOutputAudioFormat;
}
@Override
public boolean isActive() {
return !pendingOutputAudioFormat.equals(AudioFormat.NOT_SET);
}
@Override @Override
public long getDurationAfterProcessorApplied(long durationUs) { public long getDurationAfterProcessorApplied(long durationUs) {
return SpeedProviderUtil.getDurationAfterSpeedProviderApplied(speedProvider, durationUs); return SpeedProviderUtil.getDurationAfterSpeedProviderApplied(speedProvider, durationUs);
} }
@Override
public AudioFormat onConfigure(AudioFormat inputAudioFormat)
throws UnhandledAudioFormatException {
return sonicAudioProcessor.configure(inputAudioFormat);
}
@Override @Override
public void queueInput(ByteBuffer inputBuffer) { public void queueInput(ByteBuffer inputBuffer) {
long currentTimeUs = sampleCountToDurationUs(framesRead, inputAudioFormat.sampleRate); long currentTimeUs = sampleCountToDurationUs(framesRead, inputAudioFormat.sampleRate);
@ -205,14 +191,15 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
} }
@Override @Override
public void queueEndOfStream() { protected void onQueueEndOfStream() {
inputEnded = true;
if (!endOfStreamQueuedToSonic) { if (!endOfStreamQueuedToSonic) {
sonicAudioProcessor.queueEndOfStream(); sonicAudioProcessor.queueEndOfStream();
endOfStreamQueuedToSonic = true; endOfStreamQueuedToSonic = true;
} }
} }
// Not using BaseAudioProcessor's buffers.
@SuppressLint("MissingSuperCall")
@Override @Override
public ByteBuffer getOutput() { public ByteBuffer getOutput() {
ByteBuffer output = sonicAudioProcessor.getOutput(); ByteBuffer output = sonicAudioProcessor.getOutput();
@ -222,24 +209,18 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
@Override @Override
public boolean isEnded() { public boolean isEnded() {
return inputEnded && sonicAudioProcessor.isEnded(); return super.isEnded() && sonicAudioProcessor.isEnded();
} }
@Override @Override
public void flush() { protected void onFlush() {
inputEnded = false; resetState();
inputAudioFormat = pendingInputAudioFormat;
resetInternalState();
sonicAudioProcessor.flush(); sonicAudioProcessor.flush();
} }
@Override @Override
public void reset() { protected void onReset() {
flush(); resetState();
pendingInputAudioFormat = AudioFormat.NOT_SET;
pendingOutputAudioFormat = AudioFormat.NOT_SET;
inputAudioFormat = AudioFormat.NOT_SET;
resetInternalState();
sonicAudioProcessor.reset(); sonicAudioProcessor.reset();
} }
@ -371,6 +352,7 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
// Invalidate any previously created buffers in SonicAudioProcessor and the base class. // Invalidate any previously created buffers in SonicAudioProcessor and the base class.
sonicAudioProcessor.flush(); sonicAudioProcessor.flush();
endOfStreamQueuedToSonic = false; endOfStreamQueuedToSonic = false;
super.getOutput();
} }
} }
} }
@ -414,7 +396,7 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
@EnsuresNonNull({"inputSegmentStartTimesUs", "outputSegmentStartTimesUs"}) @EnsuresNonNull({"inputSegmentStartTimesUs", "outputSegmentStartTimesUs"})
@RequiresNonNull("lock") @RequiresNonNull("lock")
private void resetInternalState(@UnknownInitialization SpeedChangingAudioProcessor this) { private void resetState(@UnknownInitialization SpeedChangingAudioProcessor this) {
synchronized (lock) { synchronized (lock) {
inputSegmentStartTimesUs = new LongArray(); inputSegmentStartTimesUs = new LongArray();
outputSegmentStartTimesUs = new LongArray(); outputSegmentStartTimesUs = new LongArray();

View file

@ -701,28 +701,6 @@ public class SpeedChangingAudioProcessorTest {
/* speedProvider= */ null, AUDIO_FORMAT.sampleRate, /* inputSamples= */ 1000L)); /* speedProvider= */ null, AUDIO_FORMAT.sampleRate, /* inputSamples= */ 1000L));
} }
@Test
public void isActive_beforeConfigure_returnsFalse() {
SpeedProvider speedProvider =
TestSpeedProvider.createWithFrameCounts(
AUDIO_FORMAT, /* frameCounts= */ new int[] {1000}, /* speeds= */ new float[] {2f});
SpeedChangingAudioProcessor processor = new SpeedChangingAudioProcessor(speedProvider);
assertThat(processor.isActive()).isFalse();
}
@Test
public void isActive_afterConfigure_returnsTrue()
throws AudioProcessor.UnhandledAudioFormatException {
SpeedProvider speedProvider =
TestSpeedProvider.createWithFrameCounts(
AUDIO_FORMAT, /* frameCounts= */ new int[] {1000}, /* speeds= */ new float[] {2f});
SpeedChangingAudioProcessor processor = new SpeedChangingAudioProcessor(speedProvider);
processor.configure(AUDIO_FORMAT);
assertThat(processor.isActive()).isTrue();
}
private static SpeedChangingAudioProcessor getConfiguredSpeedChangingAudioProcessor( private static SpeedChangingAudioProcessor getConfiguredSpeedChangingAudioProcessor(
SpeedProvider speedProvider) throws AudioProcessor.UnhandledAudioFormatException { SpeedProvider speedProvider) throws AudioProcessor.UnhandledAudioFormatException {
SpeedChangingAudioProcessor speedChangingAudioProcessor = SpeedChangingAudioProcessor speedChangingAudioProcessor =