SpeedChangingAudioProcessor: process all callbacks after audio ends

PiperOrigin-RevId: 616143969
This commit is contained in:
tofunmi 2024-03-15 08:51:44 -07:00 committed by Copybara-Service
parent b126bae93d
commit b9843af6a0
2 changed files with 61 additions and 2 deletions

View File

@ -182,6 +182,9 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
* <p>Calls {@linkplain LongConsumer#accept(long) the callback} with the output time as soon as
* enough audio has been processed to calculate it.
*
* <p>If the audio processor has ended, speeds will come out at the last processed speed of the
* audio processor.
*
* <p>Successive calls must have monotonically increasing {@code inputTimeUs}.
*
* <p>Can be called from any thread.
@ -192,7 +195,7 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
*/
public void getSpeedAdjustedTimeAsync(long inputTimeUs, LongConsumer callback) {
synchronized (pendingCallbacksLock) {
if (inputTimeUs <= lastProcessedInputTime) {
if (inputTimeUs <= lastProcessedInputTime || isEnded()) {
callback.accept(calculateSpeedAdjustedTime(inputTimeUs));
return;
}
@ -234,7 +237,7 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
private void processPendingCallbacks() {
synchronized (pendingCallbacksLock) {
while (!pendingCallbacks.isEmpty()
&& pendingCallbackInputTimesUs.element() <= lastProcessedInputTime) {
&& (pendingCallbackInputTimesUs.element() <= lastProcessedInputTime || isEnded())) {
pendingCallbacks
.remove()
.accept(calculateSpeedAdjustedTime(pendingCallbackInputTimesUs.remove()));

View File

@ -16,6 +16,7 @@
package androidx.media3.common.audio;
import static androidx.media3.common.audio.AudioProcessor.EMPTY_BUFFER;
import static androidx.media3.common.util.Assertions.checkState;
import static com.google.common.truth.Truth.assertThat;
import androidx.media3.common.C;
@ -378,6 +379,61 @@ public class SpeedChangingAudioProcessorTest {
assertThat(outputTimesUs).containsExactly(25L, 50L, 93L);
}
@Test
public void getSpeedAdjustedTimeAsync_timeAfterEndTime_callbacksCalledWithCorrectParameters()
throws Exception {
ArrayList<Long> outputTimesUs = new ArrayList<>();
// The speed change is at 113Us (5*MICROS_PER_SECOND/sampleRate).
SpeedProvider speedProvider =
TestSpeedProvider.createWithFrameCounts(
AUDIO_FORMAT, /* frameCounts= */ new int[] {5, 5}, /* speeds= */ new float[] {2, 1});
SpeedChangingAudioProcessor speedChangingAudioProcessor =
getConfiguredSpeedChangingAudioProcessor(speedProvider);
ByteBuffer inputBuffer = getInputBuffer(/* frameCount= */ 3);
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
/* inputTimeUs= */ 300L, outputTimesUs::add);
speedChangingAudioProcessor.queueInput(inputBuffer);
getAudioProcessorOutput(speedChangingAudioProcessor);
inputBuffer.rewind();
speedChangingAudioProcessor.queueInput(inputBuffer);
getAudioProcessorOutput(speedChangingAudioProcessor);
inputBuffer.rewind();
speedChangingAudioProcessor.queueInput(inputBuffer);
speedChangingAudioProcessor.queueEndOfStream();
getAudioProcessorOutput(speedChangingAudioProcessor);
// 150 is after the speed change so floor(113 / 2 + (300 - 113)*1) -> 243
assertThat(outputTimesUs).containsExactly(243L);
}
@Test
public void
getSpeedAdjustedTimeAsync_timeAfterEndTimeAfterProcessorEnded_callbacksCalledWithCorrectParameters()
throws Exception {
ArrayList<Long> outputTimesUs = new ArrayList<>();
// The speed change is at 113Us (5*MICROS_PER_SECOND/sampleRate).
SpeedProvider speedProvider =
TestSpeedProvider.createWithFrameCounts(
AUDIO_FORMAT, /* frameCounts= */ new int[] {5, 5}, /* speeds= */ new float[] {2, 1});
SpeedChangingAudioProcessor speedChangingAudioProcessor =
getConfiguredSpeedChangingAudioProcessor(speedProvider);
ByteBuffer inputBuffer = getInputBuffer(/* frameCount= */ 5);
speedChangingAudioProcessor.queueInput(inputBuffer);
getAudioProcessorOutput(speedChangingAudioProcessor);
inputBuffer.rewind();
speedChangingAudioProcessor.queueInput(inputBuffer);
speedChangingAudioProcessor.queueEndOfStream();
getAudioProcessorOutput(speedChangingAudioProcessor);
checkState(speedChangingAudioProcessor.isEnded());
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
/* inputTimeUs= */ 300L, outputTimesUs::add);
// 150 is after the speed change so floor(113 / 2 + (300 - 113)*1) -> 243
assertThat(outputTimesUs).containsExactly(243L);
}
private static SpeedChangingAudioProcessor getConfiguredSpeedChangingAudioProcessor(
SpeedProvider speedProvider) throws AudioProcessor.UnhandledAudioFormatException {
SpeedChangingAudioProcessor speedChangingAudioProcessor =