diff --git a/libraries/common/src/main/java/androidx/media3/common/audio/SpeedChangingAudioProcessor.java b/libraries/common/src/main/java/androidx/media3/common/audio/SpeedChangingAudioProcessor.java index 35ccbe843a..ebf8661a02 100644 --- a/libraries/common/src/main/java/androidx/media3/common/audio/SpeedChangingAudioProcessor.java +++ b/libraries/common/src/main/java/androidx/media3/common/audio/SpeedChangingAudioProcessor.java @@ -27,6 +27,7 @@ import androidx.media3.common.util.SpeedProviderUtil; import androidx.media3.common.util.TimestampConsumer; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; +import java.math.RoundingMode; import java.nio.ByteBuffer; import java.util.ArrayDeque; import java.util.Queue; @@ -117,11 +118,12 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor { if (nextSpeedChangeTimeUs != C.TIME_UNSET) { bytesToNextSpeedChange = (int) - Util.scaleLargeTimestamp( + Util.scaleLargeValue( /* timestamp= */ nextSpeedChangeTimeUs - timeUs, /* multiplier= */ (long) inputAudioFormat.sampleRate * inputAudioFormat.bytesPerFrame, - /* divisor= */ C.MICROS_PER_SECOND); + /* divisor= */ C.MICROS_PER_SECOND, + RoundingMode.CEILING); int bytesToNextFrame = inputAudioFormat.bytesPerFrame - bytesToNextSpeedChange % inputAudioFormat.bytesPerFrame; if (bytesToNextFrame != inputAudioFormat.bytesPerFrame) { diff --git a/libraries/common/src/test/java/androidx/media3/common/audio/SpeedChangingAudioProcessorTest.java b/libraries/common/src/test/java/androidx/media3/common/audio/SpeedChangingAudioProcessorTest.java index b6df1aa4da..1a681a09f5 100644 --- a/libraries/common/src/test/java/androidx/media3/common/audio/SpeedChangingAudioProcessorTest.java +++ b/libraries/common/src/test/java/androidx/media3/common/audio/SpeedChangingAudioProcessorTest.java @@ -239,6 +239,25 @@ public class SpeedChangingAudioProcessorTest { assertThat(inputBuffer.limit()).isEqualTo(inputBufferLimit); } + @Test + public void queueInput_multipleSpeedsInBufferWithLimitVeryClose_readsDataUntilSpeedLimit() + throws Exception { + long speedChangeTimeUs = 1; // Change speed very close to current position at 1us. + SpeedProvider speedProvider = + TestSpeedProvider.createWithStartTimes( + /* startTimesUs= */ new long[] {0L, speedChangeTimeUs}, + /* speeds= */ new float[] {1, 2}); + SpeedChangingAudioProcessor speedChangingAudioProcessor = + getConfiguredSpeedChangingAudioProcessor(speedProvider); + ByteBuffer inputBuffer = getInputBuffer(/* frameCount= */ 5); + int inputBufferLimit = inputBuffer.limit(); + + speedChangingAudioProcessor.queueInput(inputBuffer); + + assertThat(inputBuffer.position()).isEqualTo(AUDIO_FORMAT.bytesPerFrame); + assertThat(inputBuffer.limit()).isEqualTo(inputBufferLimit); + } + @Test public void queueEndOfStream_afterNoSpeedChangeAndWithOutputRetrieved_endsProcessor() throws Exception {