Round bytesToNextSpeedChange up instead of down

Rounding down means that very small diferrences (e.g. 1 us) result
in bytesToNextSpeedChange==0, which stalls progress forever as no
new bytes are read. Rounding up instead ensures that we always read
at least one audio frame if nextSpeedChangeTimeUs is in the future.

PiperOrigin-RevId: 632116560
This commit is contained in:
tonihei 2024-05-09 05:33:51 -07:00 committed by Copybara-Service
parent 49fa343127
commit 971486f5f9
2 changed files with 23 additions and 2 deletions

View File

@ -27,6 +27,7 @@ import androidx.media3.common.util.SpeedProviderUtil;
import androidx.media3.common.util.TimestampConsumer; import androidx.media3.common.util.TimestampConsumer;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import java.math.RoundingMode;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Queue; import java.util.Queue;
@ -117,11 +118,12 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
if (nextSpeedChangeTimeUs != C.TIME_UNSET) { if (nextSpeedChangeTimeUs != C.TIME_UNSET) {
bytesToNextSpeedChange = bytesToNextSpeedChange =
(int) (int)
Util.scaleLargeTimestamp( Util.scaleLargeValue(
/* timestamp= */ nextSpeedChangeTimeUs - timeUs, /* timestamp= */ nextSpeedChangeTimeUs - timeUs,
/* multiplier= */ (long) inputAudioFormat.sampleRate /* multiplier= */ (long) inputAudioFormat.sampleRate
* inputAudioFormat.bytesPerFrame, * inputAudioFormat.bytesPerFrame,
/* divisor= */ C.MICROS_PER_SECOND); /* divisor= */ C.MICROS_PER_SECOND,
RoundingMode.CEILING);
int bytesToNextFrame = int bytesToNextFrame =
inputAudioFormat.bytesPerFrame - bytesToNextSpeedChange % inputAudioFormat.bytesPerFrame; inputAudioFormat.bytesPerFrame - bytesToNextSpeedChange % inputAudioFormat.bytesPerFrame;
if (bytesToNextFrame != inputAudioFormat.bytesPerFrame) { if (bytesToNextFrame != inputAudioFormat.bytesPerFrame) {

View File

@ -239,6 +239,25 @@ public class SpeedChangingAudioProcessorTest {
assertThat(inputBuffer.limit()).isEqualTo(inputBufferLimit); 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 @Test
public void queueEndOfStream_afterNoSpeedChangeAndWithOutputRetrieved_endsProcessor() public void queueEndOfStream_afterNoSpeedChangeAndWithOutputRetrieved_endsProcessor()
throws Exception { throws Exception {