mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
parent
e9b82ee951
commit
492574bded
@ -21,24 +21,25 @@ import static androidx.media3.common.util.Assertions.checkState;
|
|||||||
import static androidx.media3.common.util.SpeedProviderUtil.getNextSpeedChangeSamplePosition;
|
import static androidx.media3.common.util.SpeedProviderUtil.getNextSpeedChangeSamplePosition;
|
||||||
import static androidx.media3.common.util.SpeedProviderUtil.getSampleAlignedSpeed;
|
import static androidx.media3.common.util.SpeedProviderUtil.getSampleAlignedSpeed;
|
||||||
import static androidx.media3.common.util.Util.sampleCountToDurationUs;
|
import static androidx.media3.common.util.Util.sampleCountToDurationUs;
|
||||||
import static androidx.media3.common.util.Util.scaleLargeValue;
|
|
||||||
import static java.lang.Math.min;
|
import static java.lang.Math.min;
|
||||||
|
import static java.lang.Math.round;
|
||||||
|
|
||||||
import androidx.annotation.GuardedBy;
|
import androidx.annotation.GuardedBy;
|
||||||
import androidx.annotation.IntRange;
|
import androidx.annotation.IntRange;
|
||||||
import androidx.annotation.VisibleForTesting;
|
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.util.LongArray;
|
||||||
import androidx.media3.common.util.LongArrayQueue;
|
import androidx.media3.common.util.LongArrayQueue;
|
||||||
import androidx.media3.common.util.SpeedProviderUtil;
|
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 java.math.RoundingMode;
|
import androidx.media3.common.util.Util;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.function.LongConsumer;
|
import java.util.function.LongConsumer;
|
||||||
import org.checkerframework.checker.initialization.qual.UnknownInitialization;
|
import org.checkerframework.checker.initialization.qual.UnknownInitialization;
|
||||||
|
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
||||||
|
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.
|
||||||
@ -66,12 +67,34 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
|
|||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
private final Queue<TimestampConsumer> pendingCallbacks;
|
private final Queue<TimestampConsumer> pendingCallbacks;
|
||||||
|
|
||||||
|
// Elements in the same positions in the arrays are associated.
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private LongArray inputSegmentStartTimesUs;
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private LongArray outputSegmentStartTimesUs;
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private long lastProcessedInputTimeUs;
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private long lastSpeedAdjustedInputTimeUs;
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private long lastSpeedAdjustedOutputTimeUs;
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private long speedAdjustedTimeAsyncInputTimeUs;
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
private float currentSpeed;
|
private float currentSpeed;
|
||||||
|
|
||||||
private long framesRead;
|
private long framesRead;
|
||||||
|
|
||||||
private boolean endOfStreamQueuedToSonic;
|
private boolean endOfStreamQueuedToSonic;
|
||||||
|
|
||||||
/** The current input audio format. */
|
/** The current input audio format. */
|
||||||
@GuardedBy("lock")
|
|
||||||
private AudioFormat inputAudioFormat;
|
private AudioFormat inputAudioFormat;
|
||||||
|
|
||||||
private AudioFormat pendingInputAudioFormat;
|
private AudioFormat pendingInputAudioFormat;
|
||||||
@ -89,6 +112,7 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
|
|||||||
new SynchronizedSonicAudioProcessor(lock, /* keepActiveWithDefaultParameters= */ true);
|
new SynchronizedSonicAudioProcessor(lock, /* keepActiveWithDefaultParameters= */ true);
|
||||||
pendingCallbackInputTimesUs = new LongArrayQueue();
|
pendingCallbackInputTimesUs = new LongArrayQueue();
|
||||||
pendingCallbacks = new ArrayDeque<>();
|
pendingCallbacks = new ArrayDeque<>();
|
||||||
|
speedAdjustedTimeAsyncInputTimeUs = C.TIME_UNSET;
|
||||||
resetInternalState(/* shouldResetSpeed= */ true);
|
resetInternalState(/* shouldResetSpeed= */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,10 +120,10 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
|
|||||||
public static long getSampleCountAfterProcessorApplied(
|
public static long getSampleCountAfterProcessorApplied(
|
||||||
SpeedProvider speedProvider,
|
SpeedProvider speedProvider,
|
||||||
@IntRange(from = 1) int inputSampleRateHz,
|
@IntRange(from = 1) int inputSampleRateHz,
|
||||||
@IntRange(from = 0) long inputSamples) {
|
@IntRange(from = 1) long inputSamples) {
|
||||||
checkArgument(speedProvider != null);
|
checkArgument(speedProvider != null);
|
||||||
checkArgument(inputSampleRateHz > 0);
|
checkArgument(inputSampleRateHz > 0);
|
||||||
checkArgument(inputSamples >= 0);
|
checkArgument(inputSamples > 0);
|
||||||
|
|
||||||
long outputSamples = 0;
|
long outputSamples = 0;
|
||||||
long positionSamples = 0;
|
long positionSamples = 0;
|
||||||
@ -147,22 +171,18 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void queueInput(ByteBuffer inputBuffer) {
|
public void queueInput(ByteBuffer inputBuffer) {
|
||||||
AudioFormat format;
|
long currentTimeUs = sampleCountToDurationUs(framesRead, inputAudioFormat.sampleRate);
|
||||||
synchronized (lock) {
|
float newSpeed = getSampleAlignedSpeed(speedProvider, framesRead, inputAudioFormat.sampleRate);
|
||||||
format = inputAudioFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
float newSpeed = getSampleAlignedSpeed(speedProvider, framesRead, format.sampleRate);
|
|
||||||
long nextSpeedChangeSamplePosition =
|
long nextSpeedChangeSamplePosition =
|
||||||
getNextSpeedChangeSamplePosition(speedProvider, framesRead, format.sampleRate);
|
getNextSpeedChangeSamplePosition(speedProvider, framesRead, inputAudioFormat.sampleRate);
|
||||||
|
|
||||||
updateSpeed(newSpeed);
|
updateSpeed(newSpeed, currentTimeUs);
|
||||||
|
|
||||||
int inputBufferLimit = inputBuffer.limit();
|
int inputBufferLimit = inputBuffer.limit();
|
||||||
int bytesToNextSpeedChange;
|
int bytesToNextSpeedChange;
|
||||||
if (nextSpeedChangeSamplePosition != C.INDEX_UNSET) {
|
if (nextSpeedChangeSamplePosition != C.INDEX_UNSET) {
|
||||||
bytesToNextSpeedChange =
|
bytesToNextSpeedChange =
|
||||||
(int) ((nextSpeedChangeSamplePosition - framesRead) * format.bytesPerFrame);
|
(int) ((nextSpeedChangeSamplePosition - framesRead) * inputAudioFormat.bytesPerFrame);
|
||||||
// Update the input buffer limit to make sure that all samples processed have the same speed.
|
// Update the input buffer limit to make sure that all samples processed have the same speed.
|
||||||
inputBuffer.limit(min(inputBufferLimit, inputBuffer.position() + bytesToNextSpeedChange));
|
inputBuffer.limit(min(inputBufferLimit, inputBuffer.position() + bytesToNextSpeedChange));
|
||||||
} else {
|
} else {
|
||||||
@ -177,8 +197,10 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
|
|||||||
endOfStreamQueuedToSonic = true;
|
endOfStreamQueuedToSonic = true;
|
||||||
}
|
}
|
||||||
long bytesRead = inputBuffer.position() - startPosition;
|
long bytesRead = inputBuffer.position() - startPosition;
|
||||||
checkState(bytesRead % format.bytesPerFrame == 0, "A frame was not queued completely.");
|
checkState(
|
||||||
framesRead += bytesRead / format.bytesPerFrame;
|
bytesRead % inputAudioFormat.bytesPerFrame == 0, "A frame was not queued completely.");
|
||||||
|
framesRead += bytesRead / inputAudioFormat.bytesPerFrame;
|
||||||
|
updateLastProcessedInputTime();
|
||||||
inputBuffer.limit(inputBufferLimit);
|
inputBuffer.limit(inputBufferLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +215,9 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer getOutput() {
|
public ByteBuffer getOutput() {
|
||||||
return sonicAudioProcessor.getOutput();
|
ByteBuffer output = sonicAudioProcessor.getOutput();
|
||||||
|
processPendingCallbacks();
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -204,12 +228,9 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
|
|||||||
@Override
|
@Override
|
||||||
public void flush() {
|
public void flush() {
|
||||||
inputEnded = false;
|
inputEnded = false;
|
||||||
|
inputAudioFormat = pendingInputAudioFormat;
|
||||||
resetInternalState(/* shouldResetSpeed= */ false);
|
resetInternalState(/* shouldResetSpeed= */ false);
|
||||||
synchronized (lock) {
|
sonicAudioProcessor.flush();
|
||||||
inputAudioFormat = pendingInputAudioFormat;
|
|
||||||
sonicAudioProcessor.flush();
|
|
||||||
processPendingCallbacks();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -217,11 +238,7 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
|
|||||||
flush();
|
flush();
|
||||||
pendingInputAudioFormat = AudioFormat.NOT_SET;
|
pendingInputAudioFormat = AudioFormat.NOT_SET;
|
||||||
pendingOutputAudioFormat = AudioFormat.NOT_SET;
|
pendingOutputAudioFormat = AudioFormat.NOT_SET;
|
||||||
synchronized (lock) {
|
inputAudioFormat = AudioFormat.NOT_SET;
|
||||||
inputAudioFormat = AudioFormat.NOT_SET;
|
|
||||||
pendingCallbackInputTimesUs.clear();
|
|
||||||
pendingCallbacks.clear();
|
|
||||||
}
|
|
||||||
resetInternalState(/* shouldResetSpeed= */ true);
|
resetInternalState(/* shouldResetSpeed= */ true);
|
||||||
sonicAudioProcessor.reset();
|
sonicAudioProcessor.reset();
|
||||||
}
|
}
|
||||||
@ -244,125 +261,154 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
|
|||||||
* @param callback The callback called with the output time. May be called on a different thread
|
* @param callback The callback called with the output time. May be called on a different thread
|
||||||
* from the caller of this method.
|
* from the caller of this method.
|
||||||
*/
|
*/
|
||||||
// TODO(b/381553948): Accept an executor on which to dispatch the callback.
|
|
||||||
public void getSpeedAdjustedTimeAsync(long inputTimeUs, TimestampConsumer callback) {
|
public void getSpeedAdjustedTimeAsync(long inputTimeUs, TimestampConsumer callback) {
|
||||||
int sampleRate;
|
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
sampleRate = inputAudioFormat.sampleRate;
|
checkArgument(speedAdjustedTimeAsyncInputTimeUs < inputTimeUs);
|
||||||
|
speedAdjustedTimeAsyncInputTimeUs = inputTimeUs;
|
||||||
if (sampleRate == Format.NO_VALUE) {
|
if ((inputTimeUs <= lastProcessedInputTimeUs && pendingCallbackInputTimesUs.isEmpty())
|
||||||
pendingCallbackInputTimesUs.add(inputTimeUs);
|
|| isEnded()) {
|
||||||
pendingCallbacks.add(callback);
|
callback.onTimestamp(calculateSpeedAdjustedTime(inputTimeUs));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
pendingCallbackInputTimesUs.add(inputTimeUs);
|
||||||
|
pendingCallbacks.add(callback);
|
||||||
}
|
}
|
||||||
// TODO(b/381553948): Use an executor to invoke callback.
|
|
||||||
callback.onTimestamp(
|
|
||||||
getDurationUsAfterProcessorApplied(speedProvider, sampleRate, inputTimeUs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the input media duration in microseconds for the given playout duration.
|
* Returns the input media duration for the given playout duration.
|
||||||
*
|
*
|
||||||
* <p>This method returns the inverse of {@link #getSpeedAdjustedTimeAsync} when the instance has
|
* <p>Both durations are counted from the last {@link #reset()} or {@link #flush()} of the audio
|
||||||
* been configured and flushed. Otherwise, it returns {@code playoutDurationUs}.
|
* processor.
|
||||||
|
*
|
||||||
|
* <p>The {@code playoutDurationUs} must be less than last processed buffer output time.
|
||||||
*
|
*
|
||||||
* @param playoutDurationUs The playout duration in microseconds.
|
* @param playoutDurationUs The playout duration in microseconds.
|
||||||
|
* @return The corresponding input duration in microseconds.
|
||||||
*/
|
*/
|
||||||
public long getMediaDurationUs(long playoutDurationUs) {
|
public long getMediaDurationUs(long playoutDurationUs) {
|
||||||
int sampleRate;
|
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
sampleRate = inputAudioFormat.sampleRate;
|
int floorIndex = outputSegmentStartTimesUs.size() - 1;
|
||||||
|
while (floorIndex > 0 && outputSegmentStartTimesUs.get(floorIndex) > playoutDurationUs) {
|
||||||
|
floorIndex--;
|
||||||
|
}
|
||||||
|
long lastSegmentOutputDurationUs =
|
||||||
|
playoutDurationUs - outputSegmentStartTimesUs.get(floorIndex);
|
||||||
|
long lastSegmentInputDurationUs;
|
||||||
|
if (floorIndex == outputSegmentStartTimesUs.size() - 1) {
|
||||||
|
lastSegmentInputDurationUs = getMediaDurationUsAtCurrentSpeed(lastSegmentOutputDurationUs);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
lastSegmentInputDurationUs =
|
||||||
|
round(
|
||||||
|
lastSegmentOutputDurationUs
|
||||||
|
* divide(
|
||||||
|
inputSegmentStartTimesUs.get(floorIndex + 1)
|
||||||
|
- inputSegmentStartTimesUs.get(floorIndex),
|
||||||
|
outputSegmentStartTimesUs.get(floorIndex + 1)
|
||||||
|
- outputSegmentStartTimesUs.get(floorIndex)));
|
||||||
|
}
|
||||||
|
return inputSegmentStartTimesUs.get(floorIndex) + lastSegmentInputDurationUs;
|
||||||
}
|
}
|
||||||
if (sampleRate == Format.NO_VALUE) {
|
|
||||||
return playoutDurationUs;
|
|
||||||
}
|
|
||||||
long outputSamples =
|
|
||||||
scaleLargeValue(playoutDurationUs, sampleRate, C.MICROS_PER_SECOND, RoundingMode.HALF_EVEN);
|
|
||||||
long inputSamples = getInputFrameCountForOutput(speedProvider, sampleRate, outputSamples);
|
|
||||||
return sampleCountToDurationUs(inputSamples, sampleRate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of input frames needed to output a specific number of frames, given a speed
|
* Assuming enough audio has been processed, calculates the time at which the {@code inputTimeUs}
|
||||||
* provider, input sample rate, and number of output frames.
|
* is outputted at after the speed changes has been applied.
|
||||||
*
|
|
||||||
* <p>This is the inverse operation of {@link #getSampleCountAfterProcessorApplied}.
|
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@SuppressWarnings("GuardedBy") // All call sites are guarded.
|
||||||
/* package */ static long getInputFrameCountForOutput(
|
private long calculateSpeedAdjustedTime(long inputTimeUs) {
|
||||||
SpeedProvider speedProvider,
|
int floorIndex = inputSegmentStartTimesUs.size() - 1;
|
||||||
@IntRange(from = 1) int inputSampleRate,
|
while (floorIndex > 0 && inputSegmentStartTimesUs.get(floorIndex) > inputTimeUs) {
|
||||||
@IntRange(from = 0) long outputFrameCount) {
|
floorIndex--;
|
||||||
checkArgument(inputSampleRate > 0);
|
|
||||||
checkArgument(outputFrameCount >= 0);
|
|
||||||
|
|
||||||
long inputSampleCount = 0;
|
|
||||||
while (outputFrameCount > 0) {
|
|
||||||
long boundarySamples =
|
|
||||||
getNextSpeedChangeSamplePosition(speedProvider, inputSampleCount, inputSampleRate);
|
|
||||||
float speed = getSampleAlignedSpeed(speedProvider, inputSampleCount, inputSampleRate);
|
|
||||||
|
|
||||||
long outputSamplesForSection =
|
|
||||||
Sonic.getExpectedFrameCountAfterProcessorApplied(
|
|
||||||
/* inputSampleRateHz= */ inputSampleRate,
|
|
||||||
/* outputSampleRateHz= */ inputSampleRate,
|
|
||||||
/* speed= */ speed,
|
|
||||||
/* pitch= */ speed,
|
|
||||||
/* inputFrameCount= */ boundarySamples - inputSampleCount);
|
|
||||||
|
|
||||||
if (boundarySamples == C.INDEX_UNSET || outputSamplesForSection > outputFrameCount) {
|
|
||||||
inputSampleCount +=
|
|
||||||
Sonic.getExpectedInputFrameCountForOutputFrameCount(
|
|
||||||
/* inputSampleRateHz= */ inputSampleRate,
|
|
||||||
/* outputSampleRateHz= */ inputSampleRate,
|
|
||||||
/* speed= */ speed,
|
|
||||||
/* pitch= */ speed,
|
|
||||||
outputFrameCount);
|
|
||||||
outputFrameCount = 0;
|
|
||||||
} else {
|
|
||||||
outputFrameCount -= outputSamplesForSection;
|
|
||||||
inputSampleCount = boundarySamples;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
long lastSegmentOutputDurationUs;
|
||||||
return inputSampleCount;
|
if (floorIndex == inputSegmentStartTimesUs.size() - 1) {
|
||||||
|
if (lastSpeedAdjustedInputTimeUs < inputSegmentStartTimesUs.get(floorIndex)) {
|
||||||
|
lastSpeedAdjustedInputTimeUs = inputSegmentStartTimesUs.get(floorIndex);
|
||||||
|
lastSpeedAdjustedOutputTimeUs = outputSegmentStartTimesUs.get(floorIndex);
|
||||||
|
}
|
||||||
|
long lastSegmentInputDurationUs = inputTimeUs - lastSpeedAdjustedInputTimeUs;
|
||||||
|
lastSegmentOutputDurationUs = getPlayoutDurationUsAtCurrentSpeed(lastSegmentInputDurationUs);
|
||||||
|
} else {
|
||||||
|
long lastSegmentInputDurationUs = inputTimeUs - lastSpeedAdjustedInputTimeUs;
|
||||||
|
lastSegmentOutputDurationUs =
|
||||||
|
round(
|
||||||
|
lastSegmentInputDurationUs
|
||||||
|
* divide(
|
||||||
|
outputSegmentStartTimesUs.get(floorIndex + 1)
|
||||||
|
- outputSegmentStartTimesUs.get(floorIndex),
|
||||||
|
inputSegmentStartTimesUs.get(floorIndex + 1)
|
||||||
|
- inputSegmentStartTimesUs.get(floorIndex)));
|
||||||
|
}
|
||||||
|
lastSpeedAdjustedInputTimeUs = inputTimeUs;
|
||||||
|
lastSpeedAdjustedOutputTimeUs += lastSegmentOutputDurationUs;
|
||||||
|
return lastSpeedAdjustedOutputTimeUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long getDurationUsAfterProcessorApplied(
|
private static double divide(long dividend, long divisor) {
|
||||||
SpeedProvider speedProvider, int sampleRate, long inputDurationUs) {
|
return ((double) dividend) / divisor;
|
||||||
long inputSamples =
|
|
||||||
scaleLargeValue(inputDurationUs, sampleRate, C.MICROS_PER_SECOND, RoundingMode.HALF_EVEN);
|
|
||||||
long outputSamples =
|
|
||||||
getSampleCountAfterProcessorApplied(speedProvider, sampleRate, inputSamples);
|
|
||||||
return sampleCountToDurationUs(outputSamples, sampleRate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processPendingCallbacks() {
|
private void processPendingCallbacks() {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
if (inputAudioFormat.sampleRate == Format.NO_VALUE) {
|
while (!pendingCallbacks.isEmpty()
|
||||||
return;
|
&& (pendingCallbackInputTimesUs.element() <= lastProcessedInputTimeUs || isEnded())) {
|
||||||
}
|
pendingCallbacks
|
||||||
|
.remove()
|
||||||
while (!pendingCallbacks.isEmpty()) {
|
.onTimestamp(calculateSpeedAdjustedTime(pendingCallbackInputTimesUs.remove()));
|
||||||
long inputTimeUs = pendingCallbackInputTimesUs.remove();
|
|
||||||
TimestampConsumer consumer = pendingCallbacks.remove();
|
|
||||||
// TODO(b/381553948): Use an executor to invoke callback.
|
|
||||||
consumer.onTimestamp(
|
|
||||||
getDurationUsAfterProcessorApplied(
|
|
||||||
speedProvider, inputAudioFormat.sampleRate, inputTimeUs));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSpeed(float newSpeed) {
|
private void updateSpeed(float newSpeed, long timeUs) {
|
||||||
if (newSpeed != currentSpeed) {
|
synchronized (lock) {
|
||||||
currentSpeed = newSpeed;
|
if (newSpeed != currentSpeed) {
|
||||||
sonicAudioProcessor.setSpeed(newSpeed);
|
updateSpeedChangeArrays(timeUs);
|
||||||
sonicAudioProcessor.setPitch(newSpeed);
|
currentSpeed = newSpeed;
|
||||||
// Invalidate any previously created buffers in SonicAudioProcessor and the base class.
|
sonicAudioProcessor.setSpeed(newSpeed);
|
||||||
sonicAudioProcessor.flush();
|
sonicAudioProcessor.setPitch(newSpeed);
|
||||||
endOfStreamQueuedToSonic = false;
|
// Invalidate any previously created buffers in SonicAudioProcessor and the base class.
|
||||||
|
sonicAudioProcessor.flush();
|
||||||
|
endOfStreamQueuedToSonic = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("GuardedBy") // All call sites are guarded.
|
||||||
|
private void updateSpeedChangeArrays(long currentSpeedChangeInputTimeUs) {
|
||||||
|
long lastSpeedChangeOutputTimeUs =
|
||||||
|
outputSegmentStartTimesUs.get(outputSegmentStartTimesUs.size() - 1);
|
||||||
|
long lastSpeedChangeInputTimeUs =
|
||||||
|
inputSegmentStartTimesUs.get(inputSegmentStartTimesUs.size() - 1);
|
||||||
|
long lastSpeedSegmentMediaDurationUs =
|
||||||
|
currentSpeedChangeInputTimeUs - lastSpeedChangeInputTimeUs;
|
||||||
|
inputSegmentStartTimesUs.add(currentSpeedChangeInputTimeUs);
|
||||||
|
outputSegmentStartTimesUs.add(
|
||||||
|
lastSpeedChangeOutputTimeUs
|
||||||
|
+ getPlayoutDurationUsAtCurrentSpeed(lastSpeedSegmentMediaDurationUs));
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getPlayoutDurationUsAtCurrentSpeed(long mediaDurationUs) {
|
||||||
|
return sonicAudioProcessor.getPlayoutDuration(mediaDurationUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getMediaDurationUsAtCurrentSpeed(long playoutDurationUs) {
|
||||||
|
return sonicAudioProcessor.getMediaDuration(playoutDurationUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLastProcessedInputTime() {
|
||||||
|
synchronized (lock) {
|
||||||
|
// TODO - b/320242819: Investigate whether bytesRead can be used here rather than
|
||||||
|
// sonicAudioProcessor.getProcessedInputBytes().
|
||||||
|
long currentProcessedInputDurationUs =
|
||||||
|
Util.scaleLargeTimestamp(
|
||||||
|
/* timestamp= */ sonicAudioProcessor.getProcessedInputBytes(),
|
||||||
|
/* multiplier= */ C.MICROS_PER_SECOND,
|
||||||
|
/* divisor= */ (long) inputAudioFormat.sampleRate * inputAudioFormat.bytesPerFrame);
|
||||||
|
lastProcessedInputTimeUs =
|
||||||
|
inputSegmentStartTimesUs.get(inputSegmentStartTimesUs.size() - 1)
|
||||||
|
+ currentProcessedInputDurationUs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,12 +420,28 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
|
|||||||
*
|
*
|
||||||
* @param shouldResetSpeed Whether {@link #currentSpeed} should be reset to its default value.
|
* @param shouldResetSpeed Whether {@link #currentSpeed} should be reset to its default value.
|
||||||
*/
|
*/
|
||||||
|
@EnsuresNonNull({"inputSegmentStartTimesUs", "outputSegmentStartTimesUs"})
|
||||||
|
@RequiresNonNull("lock")
|
||||||
private void resetInternalState(
|
private void resetInternalState(
|
||||||
@UnknownInitialization SpeedChangingAudioProcessor this, boolean shouldResetSpeed) {
|
@UnknownInitialization SpeedChangingAudioProcessor this, boolean shouldResetSpeed) {
|
||||||
if (shouldResetSpeed) {
|
synchronized (lock) {
|
||||||
currentSpeed = 1f;
|
inputSegmentStartTimesUs = new LongArray();
|
||||||
|
outputSegmentStartTimesUs = new LongArray();
|
||||||
|
inputSegmentStartTimesUs.add(0);
|
||||||
|
outputSegmentStartTimesUs.add(0);
|
||||||
|
lastProcessedInputTimeUs = 0;
|
||||||
|
lastSpeedAdjustedInputTimeUs = 0;
|
||||||
|
lastSpeedAdjustedOutputTimeUs = 0;
|
||||||
|
if (shouldResetSpeed) {
|
||||||
|
currentSpeed = 1f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
framesRead = 0;
|
framesRead = 0;
|
||||||
endOfStreamQueuedToSonic = false;
|
endOfStreamQueuedToSonic = false;
|
||||||
|
// TODO: b/339842724 - This should ideally also reset speedAdjustedTimeAsyncInputTimeUs and
|
||||||
|
// clear pendingCallbacks and pendingCallbacksInputTimes. We can't do this at the moment
|
||||||
|
// because some clients register callbacks with getSpeedAdjustedTimeAsync before this audio
|
||||||
|
// processor is flushed.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
package androidx.media3.common.audio;
|
package androidx.media3.common.audio;
|
||||||
|
|
||||||
import static androidx.media3.common.audio.AudioProcessor.EMPTY_BUFFER;
|
import static androidx.media3.common.audio.AudioProcessor.EMPTY_BUFFER;
|
||||||
import static androidx.media3.common.audio.SpeedChangingAudioProcessor.getInputFrameCountForOutput;
|
import static androidx.media3.common.util.Assertions.checkState;
|
||||||
import static androidx.media3.test.utils.TestUtil.getNonRandomByteBuffer;
|
import static androidx.media3.test.utils.TestUtil.getNonRandomByteBuffer;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static org.junit.Assert.assertThrows;
|
import static org.junit.Assert.assertThrows;
|
||||||
@ -36,59 +36,53 @@ import org.junit.runner.RunWith;
|
|||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class SpeedChangingAudioProcessorTest {
|
public class SpeedChangingAudioProcessorTest {
|
||||||
|
|
||||||
private static final AudioFormat AUDIO_FORMAT_44_100HZ =
|
private static final AudioFormat AUDIO_FORMAT =
|
||||||
new AudioFormat(
|
new AudioFormat(
|
||||||
/* sampleRate= */ 44_100, /* channelCount= */ 2, /* encoding= */ C.ENCODING_PCM_16BIT);
|
/* sampleRate= */ 44100, /* channelCount= */ 2, /* encoding= */ C.ENCODING_PCM_16BIT);
|
||||||
|
|
||||||
private static final AudioFormat AUDIO_FORMAT_50_000HZ =
|
|
||||||
new AudioFormat(
|
|
||||||
/* sampleRate= */ 50_000, /* channelCount= */ 2, /* encoding= */ C.ENCODING_PCM_16BIT);
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void queueInput_noSpeedChange_doesNotOverwriteInput() throws Exception {
|
public void queueInput_noSpeedChange_doesNotOverwriteInput() throws Exception {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {1});
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {1});
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
|
|
||||||
inputBuffer.rewind();
|
inputBuffer.rewind();
|
||||||
assertThat(inputBuffer)
|
assertThat(inputBuffer)
|
||||||
.isEqualTo(
|
.isEqualTo(getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame));
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void queueInput_speedChange_doesNotOverwriteInput() throws Exception {
|
public void queueInput_speedChange_doesNotOverwriteInput() throws Exception {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
|
|
||||||
inputBuffer.rewind();
|
inputBuffer.rewind();
|
||||||
assertThat(inputBuffer)
|
assertThat(inputBuffer)
|
||||||
.isEqualTo(
|
.isEqualTo(getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame));
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void queueInput_noSpeedChange_copiesSamples() throws Exception {
|
public void queueInput_noSpeedChange_copiesSamples() throws Exception {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {1});
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {1});
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
speedChangingAudioProcessor.queueEndOfStream();
|
speedChangingAudioProcessor.queueEndOfStream();
|
||||||
@ -102,11 +96,11 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
public void queueInput_speedChange_modifiesSamples() throws Exception {
|
public void queueInput_speedChange_modifiesSamples() throws Exception {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
speedChangingAudioProcessor.queueEndOfStream();
|
speedChangingAudioProcessor.queueEndOfStream();
|
||||||
@ -121,13 +115,11 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
public void queueInput_noSpeedChangeAfterSpeedChange_copiesSamples() throws Exception {
|
public void queueInput_noSpeedChangeAfterSpeedChange_copiesSamples() throws Exception {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5, 5}, /* speeds= */ new float[] {2, 1});
|
||||||
/* frameCounts= */ new int[] {5, 5},
|
|
||||||
/* speeds= */ new float[] {2, 1});
|
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
inputBuffer.rewind();
|
inputBuffer.rewind();
|
||||||
@ -144,13 +136,11 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5, 5}, /* speeds= */ new float[] {1, 2});
|
||||||
/* frameCounts= */ new int[] {5, 5},
|
|
||||||
/* speeds= */ new float[] {1, 2});
|
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
inputBuffer.rewind();
|
inputBuffer.rewind();
|
||||||
@ -160,7 +150,7 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
|
|
||||||
speedProvider =
|
speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
||||||
speedChangingAudioProcessor = getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
speedChangingAudioProcessor = getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
inputBuffer.rewind();
|
inputBuffer.rewind();
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
@ -175,13 +165,11 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5, 5}, /* speeds= */ new float[] {3, 2});
|
||||||
/* frameCounts= */ new int[] {5, 5},
|
|
||||||
/* speeds= */ new float[] {3, 2});
|
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
inputBuffer.rewind();
|
inputBuffer.rewind();
|
||||||
@ -191,7 +179,7 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
|
|
||||||
speedProvider =
|
speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
||||||
speedChangingAudioProcessor = getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
speedChangingAudioProcessor = getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
inputBuffer.rewind();
|
inputBuffer.rewind();
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
@ -206,20 +194,18 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5, 5}, /* speeds= */ new float[] {2, 3});
|
||||||
/* frameCounts= */ new int[] {5, 5},
|
|
||||||
/* speeds= */ new float[] {2, 3});
|
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
ByteBuffer outputBuffer = getAudioProcessorOutput(speedChangingAudioProcessor);
|
ByteBuffer outputBuffer = getAudioProcessorOutput(speedChangingAudioProcessor);
|
||||||
|
|
||||||
speedProvider =
|
speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
||||||
speedChangingAudioProcessor = getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
speedChangingAudioProcessor = getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
inputBuffer.rewind();
|
inputBuffer.rewind();
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
@ -232,7 +218,7 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
@Test
|
@Test
|
||||||
public void queueInput_multipleSpeedsInBufferWithLimitAtFrameBoundary_readsDataUntilSpeedLimit()
|
public void queueInput_multipleSpeedsInBufferWithLimitAtFrameBoundary_readsDataUntilSpeedLimit()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
long speedChangeTimeUs = 4 * C.MICROS_PER_SECOND / AUDIO_FORMAT_44_100HZ.sampleRate;
|
long speedChangeTimeUs = 4 * C.MICROS_PER_SECOND / AUDIO_FORMAT.sampleRate;
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithStartTimes(
|
TestSpeedProvider.createWithStartTimes(
|
||||||
/* startTimesUs= */ new long[] {0L, speedChangeTimeUs},
|
/* startTimesUs= */ new long[] {0L, speedChangeTimeUs},
|
||||||
@ -240,19 +226,19 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
int inputBufferLimit = inputBuffer.limit();
|
int inputBufferLimit = inputBuffer.limit();
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
|
|
||||||
assertThat(inputBuffer.position()).isEqualTo(4 * AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
assertThat(inputBuffer.position()).isEqualTo(4 * AUDIO_FORMAT.bytesPerFrame);
|
||||||
assertThat(inputBuffer.limit()).isEqualTo(inputBufferLimit);
|
assertThat(inputBuffer.limit()).isEqualTo(inputBufferLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void queueInput_multipleSpeedsInBufferWithLimitInsideFrame_readsDataUntilSpeedLimit()
|
public void queueInput_multipleSpeedsInBufferWithLimitInsideFrame_readsDataUntilSpeedLimit()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
long speedChangeTimeUs = (long) (3.5 * C.MICROS_PER_SECOND / AUDIO_FORMAT_44_100HZ.sampleRate);
|
long speedChangeTimeUs = (long) (3.5 * C.MICROS_PER_SECOND / AUDIO_FORMAT.sampleRate);
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithStartTimes(
|
TestSpeedProvider.createWithStartTimes(
|
||||||
/* startTimesUs= */ new long[] {0L, speedChangeTimeUs},
|
/* startTimesUs= */ new long[] {0L, speedChangeTimeUs},
|
||||||
@ -260,12 +246,12 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
int inputBufferLimit = inputBuffer.limit();
|
int inputBufferLimit = inputBuffer.limit();
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
|
|
||||||
assertThat(inputBuffer.position()).isEqualTo(4 * AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
assertThat(inputBuffer.position()).isEqualTo(4 * AUDIO_FORMAT.bytesPerFrame);
|
||||||
assertThat(inputBuffer.limit()).isEqualTo(inputBufferLimit);
|
assertThat(inputBuffer.limit()).isEqualTo(inputBufferLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,18 +266,18 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
// SpeedChangingAudioProcessor only queues samples until the next speed change.
|
// SpeedChangingAudioProcessor only queues samples until the next speed change.
|
||||||
while (inputBuffer.hasRemaining()) {
|
while (inputBuffer.hasRemaining()) {
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
outputFrames +=
|
outputFrames +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueEndOfStream();
|
speedChangingAudioProcessor.queueEndOfStream();
|
||||||
outputFrames +=
|
outputFrames +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
// We allow 1 sample of tolerance per speed change.
|
// We allow 1 sample of tolerance per speed change.
|
||||||
assertThat(outputFrames).isWithin(1).of(3);
|
assertThat(outputFrames).isWithin(1).of(3);
|
||||||
}
|
}
|
||||||
@ -301,13 +287,11 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5, 5}, /* speeds= */ new float[] {2, 1});
|
||||||
/* frameCounts= */ new int[] {5, 5},
|
|
||||||
/* speeds= */ new float[] {2, 1});
|
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
inputBuffer.rewind();
|
inputBuffer.rewind();
|
||||||
@ -323,13 +307,11 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5, 5}, /* speeds= */ new float[] {1, 2});
|
||||||
/* frameCounts= */ new int[] {5, 5},
|
|
||||||
/* speeds= */ new float[] {1, 2});
|
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
inputBuffer.rewind();
|
inputBuffer.rewind();
|
||||||
@ -345,11 +327,11 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {1});
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {1});
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
speedChangingAudioProcessor.queueEndOfStream();
|
speedChangingAudioProcessor.queueEndOfStream();
|
||||||
@ -362,11 +344,11 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
speedChangingAudioProcessor.queueEndOfStream();
|
speedChangingAudioProcessor.queueEndOfStream();
|
||||||
@ -378,7 +360,7 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
public void queueEndOfStream_noInputQueued_endsProcessor() throws Exception {
|
public void queueEndOfStream_noInputQueued_endsProcessor() throws Exception {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
|
|
||||||
@ -391,11 +373,11 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
public void isEnded_afterNoSpeedChangeAndOutputRetrieved_isFalse() throws Exception {
|
public void isEnded_afterNoSpeedChangeAndOutputRetrieved_isFalse() throws Exception {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {1});
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {1});
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
getAudioProcessorOutput(speedChangingAudioProcessor);
|
getAudioProcessorOutput(speedChangingAudioProcessor);
|
||||||
@ -407,11 +389,11 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
public void isEnded_afterSpeedChangeAndOutputRetrieved_isFalse() throws Exception {
|
public void isEnded_afterSpeedChangeAndOutputRetrieved_isFalse() throws Exception {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5}, /* speeds= */ new float[] {2});
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer inputBuffer =
|
ByteBuffer inputBuffer =
|
||||||
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(inputBuffer);
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
getAudioProcessorOutput(speedChangingAudioProcessor);
|
getAudioProcessorOutput(speedChangingAudioProcessor);
|
||||||
@ -420,89 +402,147 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getSpeedAdjustedTimeAsync_beforeFlush_callbacksCalledWithCorrectParametersAfterFlush()
|
public void getSpeedAdjustedTimeAsync_callbacksCalledWithCorrectParameters() throws Exception {
|
||||||
throws Exception {
|
|
||||||
ArrayList<Long> outputTimesUs = new ArrayList<>();
|
ArrayList<Long> outputTimesUs = new ArrayList<>();
|
||||||
// Sample period = 20us.
|
// The speed change is at 113Us (5*MICROS_PER_SECOND/sampleRate).
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_50_000HZ,
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5, 5}, /* speeds= */ new float[] {2, 1});
|
||||||
/* frameCounts= */ new int[] {6, 6},
|
|
||||||
/* speeds= */ new float[] {2, 1});
|
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
new SpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
speedChangingAudioProcessor.configure(AUDIO_FORMAT_50_000HZ);
|
ByteBuffer inputBuffer =
|
||||||
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
|
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
|
||||||
/* inputTimeUs= */ 40L, outputTimesUs::add);
|
/* inputTimeUs= */ 50L, outputTimesUs::add);
|
||||||
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
|
getAudioProcessorOutput(speedChangingAudioProcessor);
|
||||||
|
inputBuffer.rewind();
|
||||||
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
|
getAudioProcessorOutput(speedChangingAudioProcessor);
|
||||||
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
|
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
|
||||||
/* inputTimeUs= */ 80L, outputTimesUs::add);
|
/* inputTimeUs= */ 100L, outputTimesUs::add);
|
||||||
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
|
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
|
||||||
/* inputTimeUs= */ 160L, outputTimesUs::add);
|
/* inputTimeUs= */ 150L, outputTimesUs::add);
|
||||||
|
|
||||||
assertThat(outputTimesUs).isEmpty();
|
// 150 is after the speed change so floor(113 / 2 + (150 - 113)*1) -> 93
|
||||||
speedChangingAudioProcessor.flush();
|
assertThat(outputTimesUs).containsExactly(25L, 50L, 93L);
|
||||||
assertThat(outputTimesUs).containsExactly(20L, 40L, 100L);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getSpeedAdjustedTimeAsync_afterCallToFlush_callbacksCalledWithCorrectParameters()
|
public void getSpeedAdjustedTimeAsync_afterFlush_callbacksCalledWithCorrectParameters()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
ArrayList<Long> outputTimesUs = new ArrayList<>();
|
ArrayList<Long> outputTimesUs = new ArrayList<>();
|
||||||
// Sample period = 20us.
|
// The speed change is at 113Us (5*MICROS_PER_SECOND/sampleRate). Also add another speed change
|
||||||
|
// to 3x at a later point that should not be used if the flush is handled correctly.
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_50_000HZ,
|
AUDIO_FORMAT,
|
||||||
/* frameCounts= */ new int[] {6, 6},
|
/* frameCounts= */ new int[] {5, 5, 5},
|
||||||
/* speeds= */ new float[] {2, 1});
|
/* speeds= */ new float[] {2, 1, 3});
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
new SpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
speedChangingAudioProcessor.configure(AUDIO_FORMAT_50_000HZ);
|
ByteBuffer inputBuffer =
|
||||||
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
// Use the audio processor before a flush
|
||||||
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
|
getAudioProcessorOutput(speedChangingAudioProcessor);
|
||||||
|
inputBuffer.rewind();
|
||||||
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
|
getAudioProcessorOutput(speedChangingAudioProcessor);
|
||||||
|
inputBuffer.rewind();
|
||||||
|
|
||||||
|
// Flush and use it again.
|
||||||
speedChangingAudioProcessor.flush();
|
speedChangingAudioProcessor.flush();
|
||||||
|
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
|
||||||
|
/* inputTimeUs= */ 50L, outputTimesUs::add);
|
||||||
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
|
getAudioProcessorOutput(speedChangingAudioProcessor);
|
||||||
|
inputBuffer.rewind();
|
||||||
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
|
getAudioProcessorOutput(speedChangingAudioProcessor);
|
||||||
|
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
|
||||||
|
/* inputTimeUs= */ 100L, outputTimesUs::add);
|
||||||
|
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
|
||||||
|
/* inputTimeUs= */ 150L, outputTimesUs::add);
|
||||||
|
|
||||||
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
|
// 150 is after the speed change so floor(113 / 2 + (150 - 113)*1) -> 93
|
||||||
/* inputTimeUs= */ 40L, outputTimesUs::add);
|
assertThat(outputTimesUs).containsExactly(25L, 50L, 93L);
|
||||||
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
|
|
||||||
/* inputTimeUs= */ 80L, outputTimesUs::add);
|
|
||||||
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
|
|
||||||
/* inputTimeUs= */ 160L, outputTimesUs::add);
|
|
||||||
|
|
||||||
assertThat(outputTimesUs).containsExactly(20L, 40L, 100L);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getSpeedAdjustedTimeAsync_timeAfterEndTime_callbacksCalledWithCorrectParameters()
|
public void getSpeedAdjustedTimeAsync_timeAfterEndTime_callbacksCalledWithCorrectParameters()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
ArrayList<Long> outputTimesUs = new ArrayList<>();
|
ArrayList<Long> outputTimesUs = new ArrayList<>();
|
||||||
// The speed change is at 120Us (6*MICROS_PER_SECOND/sampleRate).
|
// The speed change is at 113Us (5*MICROS_PER_SECOND/sampleRate).
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_50_000HZ,
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {5, 5}, /* speeds= */ new float[] {2, 1});
|
||||||
/* frameCounts= */ new int[] {6, 6},
|
|
||||||
/* speeds= */ new float[] {2, 1});
|
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
new SpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
speedChangingAudioProcessor.configure(AUDIO_FORMAT_50_000HZ);
|
ByteBuffer inputBuffer =
|
||||||
speedChangingAudioProcessor.flush();
|
getNonRandomByteBuffer(/* frameCount= */ 3, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
|
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 =
|
||||||
|
getNonRandomByteBuffer(/* frameCount= */ 5, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
|
getAudioProcessorOutput(speedChangingAudioProcessor);
|
||||||
|
inputBuffer.rewind();
|
||||||
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
|
speedChangingAudioProcessor.queueEndOfStream();
|
||||||
|
getAudioProcessorOutput(speedChangingAudioProcessor);
|
||||||
|
checkState(speedChangingAudioProcessor.isEnded());
|
||||||
|
|
||||||
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
|
speedChangingAudioProcessor.getSpeedAdjustedTimeAsync(
|
||||||
/* inputTimeUs= */ 300L, outputTimesUs::add);
|
/* inputTimeUs= */ 300L, outputTimesUs::add);
|
||||||
|
|
||||||
assertThat(outputTimesUs).containsExactly(240L);
|
// 150 is after the speed change so floor(113 / 2 + (300 - 113)*1) -> 243
|
||||||
|
assertThat(outputTimesUs).containsExactly(243L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getMediaDurationUs_returnsCorrectValues() throws Exception {
|
public void getMediaDurationUs_returnsCorrectValues() throws Exception {
|
||||||
// The speed changes happen every 10ms (500 samples @ 50.KHz)
|
// The speed changes happen every 10ms (441 samples @ 441.KHz)
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_50_000HZ,
|
AUDIO_FORMAT,
|
||||||
/* frameCounts= */ new int[] {500, 500, 500, 500},
|
/* frameCounts= */ new int[] {441, 441, 441, 441},
|
||||||
/* speeds= */ new float[] {2, 1, 5, 2});
|
/* speeds= */ new float[] {2, 1, 5, 2});
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
new SpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
speedChangingAudioProcessor.configure(AUDIO_FORMAT_50_000HZ);
|
ByteBuffer inputBuffer =
|
||||||
speedChangingAudioProcessor.flush();
|
getNonRandomByteBuffer(/* frameCount= */ 441 * 4, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
while (inputBuffer.position() < inputBuffer.limit()) {
|
||||||
|
speedChangingAudioProcessor.queueInput(inputBuffer);
|
||||||
|
}
|
||||||
|
getAudioProcessorOutput(speedChangingAudioProcessor);
|
||||||
|
|
||||||
// input (in ms) (0, 10, 20, 30, 40) ->
|
// input (in ms) (0, 10, 20, 30, 40) ->
|
||||||
// output (in ms) (0, 10/2, 10/2 + 10, 10/2 + 10 + 10/5, 10/2 + 10 + 10/5 + 10/2)
|
// output (in ms) (0, 10/2, 10/2 + 10, 10/2 + 10 + 10/5, 10/2 + 10 + 10/5 + 10/2)
|
||||||
@ -532,30 +572,30 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
int outputFrameCount = 0;
|
int outputFrameCount = 0;
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT,
|
||||||
/* frameCounts= */ new int[] {1000, 1000, 1000},
|
/* frameCounts= */ new int[] {1000, 1000, 1000},
|
||||||
/* speeds= */ new float[] {2, 4, 2}); // 500, 250, 500 = 1250
|
/* speeds= */ new float[] {2, 4, 2}); // 500, 250, 500 = 1250
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer input = getNonRandomByteBuffer(1000, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
ByteBuffer input = getNonRandomByteBuffer(1000, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(input);
|
speedChangingAudioProcessor.queueInput(input);
|
||||||
outputFrameCount +=
|
outputFrameCount +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
input.rewind();
|
input.rewind();
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(input);
|
speedChangingAudioProcessor.queueInput(input);
|
||||||
outputFrameCount +=
|
outputFrameCount +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
input.rewind();
|
input.rewind();
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueInput(input);
|
speedChangingAudioProcessor.queueInput(input);
|
||||||
outputFrameCount +=
|
outputFrameCount +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueEndOfStream();
|
speedChangingAudioProcessor.queueEndOfStream();
|
||||||
outputFrameCount +=
|
outputFrameCount +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
assertThat(outputFrameCount).isWithin(2).of(1250);
|
assertThat(outputFrameCount).isWithin(2).of(1250);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,17 +612,17 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
/* speeds= */ new float[] {2, 3, 8, 4});
|
/* speeds= */ new float[] {2, 3, 8, 4});
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
ByteBuffer input = getNonRandomByteBuffer(12, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
ByteBuffer input = getNonRandomByteBuffer(12, AUDIO_FORMAT.bytesPerFrame);
|
||||||
|
|
||||||
while (input.hasRemaining()) {
|
while (input.hasRemaining()) {
|
||||||
speedChangingAudioProcessor.queueInput(input);
|
speedChangingAudioProcessor.queueInput(input);
|
||||||
outputFrameCount +=
|
outputFrameCount +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
speedChangingAudioProcessor.queueEndOfStream();
|
speedChangingAudioProcessor.queueEndOfStream();
|
||||||
outputFrameCount +=
|
outputFrameCount +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
|
|
||||||
// Allow one sample of tolerance per effectively applied speed change.
|
// Allow one sample of tolerance per effectively applied speed change.
|
||||||
assertThat(outputFrameCount).isWithin(1).of(4);
|
assertThat(outputFrameCount).isWithin(1).of(4);
|
||||||
@ -593,23 +633,23 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
throws AudioProcessor.UnhandledAudioFormatException {
|
throws AudioProcessor.UnhandledAudioFormatException {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT,
|
||||||
/* frameCounts= */ new int[] {1000, 1000},
|
/* frameCounts= */ new int[] {1000, 1000},
|
||||||
/* speeds= */ new float[] {1, 2}); // 1000, 500.
|
/* speeds= */ new float[] {1, 2}); // 1000, 500.
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
// 1500 input frames falls in the middle of the 2x region.
|
// 1500 input frames falls in the middle of the 2x region.
|
||||||
ByteBuffer input = getNonRandomByteBuffer(1500, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
ByteBuffer input = getNonRandomByteBuffer(1500, AUDIO_FORMAT.bytesPerFrame);
|
||||||
int outputFrameCount = 0;
|
int outputFrameCount = 0;
|
||||||
|
|
||||||
while (input.hasRemaining()) {
|
while (input.hasRemaining()) {
|
||||||
speedChangingAudioProcessor.queueInput(input);
|
speedChangingAudioProcessor.queueInput(input);
|
||||||
outputFrameCount +=
|
outputFrameCount +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
}
|
}
|
||||||
speedChangingAudioProcessor.flush();
|
speedChangingAudioProcessor.flush();
|
||||||
outputFrameCount +=
|
outputFrameCount +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
assertThat(outputFrameCount).isEqualTo(1250);
|
assertThat(outputFrameCount).isEqualTo(1250);
|
||||||
input.rewind();
|
input.rewind();
|
||||||
|
|
||||||
@ -619,11 +659,11 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
while (input.hasRemaining()) {
|
while (input.hasRemaining()) {
|
||||||
speedChangingAudioProcessor.queueInput(input);
|
speedChangingAudioProcessor.queueInput(input);
|
||||||
outputFrameCount +=
|
outputFrameCount +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
}
|
}
|
||||||
speedChangingAudioProcessor.queueEndOfStream();
|
speedChangingAudioProcessor.queueEndOfStream();
|
||||||
outputFrameCount +=
|
outputFrameCount +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
assertThat(outputFrameCount).isWithin(1).of(2500); // 1250 * 2.
|
assertThat(outputFrameCount).isWithin(1).of(2500); // 1250 * 2.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -632,23 +672,23 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
throws AudioProcessor.UnhandledAudioFormatException {
|
throws AudioProcessor.UnhandledAudioFormatException {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT,
|
||||||
/* frameCounts= */ new int[] {1000, 1000},
|
/* frameCounts= */ new int[] {1000, 1000},
|
||||||
/* speeds= */ new float[] {2, 4}); // 500, 250.
|
/* speeds= */ new float[] {2, 4}); // 500, 250.
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
getConfiguredSpeedChangingAudioProcessor(speedProvider);
|
||||||
// 1500 input frames falls in the middle of the 2x region.
|
// 1500 input frames falls in the middle of the 2x region.
|
||||||
ByteBuffer input = getNonRandomByteBuffer(1500, AUDIO_FORMAT_44_100HZ.bytesPerFrame);
|
ByteBuffer input = getNonRandomByteBuffer(1500, AUDIO_FORMAT.bytesPerFrame);
|
||||||
int outputFrameCount = 0;
|
int outputFrameCount = 0;
|
||||||
|
|
||||||
while (input.hasRemaining()) {
|
while (input.hasRemaining()) {
|
||||||
speedChangingAudioProcessor.queueInput(input);
|
speedChangingAudioProcessor.queueInput(input);
|
||||||
outputFrameCount +=
|
outputFrameCount +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
}
|
}
|
||||||
speedChangingAudioProcessor.flush();
|
speedChangingAudioProcessor.flush();
|
||||||
outputFrameCount +=
|
outputFrameCount +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
assertThat(outputFrameCount).isWithin(1).of(625);
|
assertThat(outputFrameCount).isWithin(1).of(625);
|
||||||
input.rewind();
|
input.rewind();
|
||||||
|
|
||||||
@ -658,11 +698,11 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
while (input.hasRemaining()) {
|
while (input.hasRemaining()) {
|
||||||
speedChangingAudioProcessor.queueInput(input);
|
speedChangingAudioProcessor.queueInput(input);
|
||||||
outputFrameCount +=
|
outputFrameCount +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
}
|
}
|
||||||
speedChangingAudioProcessor.queueEndOfStream();
|
speedChangingAudioProcessor.queueEndOfStream();
|
||||||
outputFrameCount +=
|
outputFrameCount +=
|
||||||
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT_44_100HZ.bytesPerFrame;
|
speedChangingAudioProcessor.getOutput().remaining() / AUDIO_FORMAT.bytesPerFrame;
|
||||||
assertThat(outputFrameCount).isWithin(2).of(1250); // 625 * 2.
|
assertThat(outputFrameCount).isWithin(2).of(1250); // 625 * 2.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -676,7 +716,7 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
|
|
||||||
long sampleCountAfterProcessorApplied =
|
long sampleCountAfterProcessorApplied =
|
||||||
SpeedChangingAudioProcessor.getSampleCountAfterProcessorApplied(
|
SpeedChangingAudioProcessor.getSampleCountAfterProcessorApplied(
|
||||||
speedProvider, AUDIO_FORMAT_44_100HZ.sampleRate, /* inputSamples= */ 100);
|
speedProvider, AUDIO_FORMAT.sampleRate, /* inputSamples= */ 100);
|
||||||
assertThat(sampleCountAfterProcessorApplied).isEqualTo(50);
|
assertThat(sampleCountAfterProcessorApplied).isEqualTo(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -684,13 +724,13 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
public void getSampleCountAfterProcessorApplied_withMultipleSpeeds_outputsExpectedSamples() {
|
public void getSampleCountAfterProcessorApplied_withMultipleSpeeds_outputsExpectedSamples() {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT,
|
||||||
/* frameCounts= */ new int[] {100, 400, 50},
|
/* frameCounts= */ new int[] {100, 400, 50},
|
||||||
/* speeds= */ new float[] {2.f, 4f, 0.5f});
|
/* speeds= */ new float[] {2.f, 4f, 0.5f});
|
||||||
|
|
||||||
long sampleCountAfterProcessorApplied =
|
long sampleCountAfterProcessorApplied =
|
||||||
SpeedChangingAudioProcessor.getSampleCountAfterProcessorApplied(
|
SpeedChangingAudioProcessor.getSampleCountAfterProcessorApplied(
|
||||||
speedProvider, AUDIO_FORMAT_44_100HZ.sampleRate, /* inputSamples= */ 550);
|
speedProvider, AUDIO_FORMAT.sampleRate, /* inputSamples= */ 550);
|
||||||
assertThat(sampleCountAfterProcessorApplied).isEqualTo(250);
|
assertThat(sampleCountAfterProcessorApplied).isEqualTo(250);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -699,13 +739,13 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
getSampleCountAfterProcessorApplied_beyondLastSpeedRegion_stillAppliesLastSpeedValue() {
|
getSampleCountAfterProcessorApplied_beyondLastSpeedRegion_stillAppliesLastSpeedValue() {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT,
|
||||||
/* frameCounts= */ new int[] {100, 400, 50},
|
/* frameCounts= */ new int[] {100, 400, 50},
|
||||||
/* speeds= */ new float[] {2.f, 4f, 0.5f});
|
/* speeds= */ new float[] {2.f, 4f, 0.5f});
|
||||||
|
|
||||||
long sampleCountAfterProcessorApplied =
|
long sampleCountAfterProcessorApplied =
|
||||||
SpeedChangingAudioProcessor.getSampleCountAfterProcessorApplied(
|
SpeedChangingAudioProcessor.getSampleCountAfterProcessorApplied(
|
||||||
speedProvider, AUDIO_FORMAT_44_100HZ.sampleRate, /* inputSamples= */ 3000);
|
speedProvider, AUDIO_FORMAT.sampleRate, /* inputSamples= */ 3000);
|
||||||
assertThat(sampleCountAfterProcessorApplied).isEqualTo(5150);
|
assertThat(sampleCountAfterProcessorApplied).isEqualTo(5150);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -714,38 +754,38 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
getSampleCountAfterProcessorApplied_withInputCountBeyondIntRange_outputsExpectedSamples() {
|
getSampleCountAfterProcessorApplied_withInputCountBeyondIntRange_outputsExpectedSamples() {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT,
|
||||||
/* frameCounts= */ new int[] {1000, 10000, 8200},
|
/* frameCounts= */ new int[] {1000, 10000, 8200},
|
||||||
/* speeds= */ new float[] {0.2f, 8f, 0.5f});
|
/* speeds= */ new float[] {0.2f, 8f, 0.5f});
|
||||||
long sampleCountAfterProcessorApplied =
|
long sampleCountAfterProcessorApplied =
|
||||||
SpeedChangingAudioProcessor.getSampleCountAfterProcessorApplied(
|
SpeedChangingAudioProcessor.getSampleCountAfterProcessorApplied(
|
||||||
speedProvider, AUDIO_FORMAT_44_100HZ.sampleRate, /* inputSamples= */ 3_000_000_000L);
|
speedProvider, AUDIO_FORMAT.sampleRate, /* inputSamples= */ 3_000_000_000L);
|
||||||
assertThat(sampleCountAfterProcessorApplied).isEqualTo(5_999_984_250L);
|
assertThat(sampleCountAfterProcessorApplied).isEqualTo(5999984250L);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Testing range validation.
|
// Testing range validation.
|
||||||
@SuppressLint("Range")
|
@SuppressLint("Range")
|
||||||
@Test
|
@Test
|
||||||
public void getSampleCountAfterProcessorApplied_withNegativeFrameCount_throws() {
|
public void getSampleCountAfterProcessorApplied_withNegativeSampleCount_throws() {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT,
|
||||||
/* frameCounts= */ new int[] {1000, 10000, 8200},
|
/* frameCounts= */ new int[] {1000, 10000, 8200},
|
||||||
/* speeds= */ new float[] {0.2f, 8f, 0.5f});
|
/* speeds= */ new float[] {0.2f, 8f, 0.5f});
|
||||||
assertThrows(
|
assertThrows(
|
||||||
IllegalArgumentException.class,
|
IllegalArgumentException.class,
|
||||||
() ->
|
() ->
|
||||||
SpeedChangingAudioProcessor.getSampleCountAfterProcessorApplied(
|
SpeedChangingAudioProcessor.getSampleCountAfterProcessorApplied(
|
||||||
speedProvider, AUDIO_FORMAT_44_100HZ.sampleRate, /* inputSamples= */ -2L));
|
speedProvider, AUDIO_FORMAT.sampleRate, /* inputSamples= */ -2L));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Testing range validation.
|
// Testing range validation.
|
||||||
@SuppressLint("Range")
|
@SuppressLint("Range")
|
||||||
@Test
|
@Test
|
||||||
public void getSampleCountAfterProcessorApplied_withZeroFrameRate_throws() {
|
public void getSampleCountAfterProcessorApplied_withZeroSampleRate_throws() {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT,
|
||||||
/* frameCounts= */ new int[] {1000, 10000, 8200},
|
/* frameCounts= */ new int[] {1000, 10000, 8200},
|
||||||
/* speeds= */ new float[] {0.2f, 8f, 0.5f});
|
/* speeds= */ new float[] {0.2f, 8f, 0.5f});
|
||||||
assertThrows(
|
assertThrows(
|
||||||
@ -761,32 +801,14 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
IllegalArgumentException.class,
|
IllegalArgumentException.class,
|
||||||
() ->
|
() ->
|
||||||
SpeedChangingAudioProcessor.getSampleCountAfterProcessorApplied(
|
SpeedChangingAudioProcessor.getSampleCountAfterProcessorApplied(
|
||||||
/* speedProvider= */ null,
|
/* speedProvider= */ null, AUDIO_FORMAT.sampleRate, /* inputSamples= */ 1000L));
|
||||||
AUDIO_FORMAT_44_100HZ.sampleRate,
|
|
||||||
/* inputSamples= */ 1000L));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getSampleCountAfterProcessorApplied_withZeroInputFrames_returnsZero() {
|
|
||||||
SpeedProvider speedProvider =
|
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
|
||||||
AUDIO_FORMAT_44_100HZ,
|
|
||||||
/* frameCounts= */ new int[] {1000, 10000, 8200},
|
|
||||||
/* speeds= */ new float[] {0.2f, 8f, 0.5f});
|
|
||||||
|
|
||||||
long sampleCountAfterProcessorApplied =
|
|
||||||
SpeedChangingAudioProcessor.getSampleCountAfterProcessorApplied(
|
|
||||||
speedProvider, AUDIO_FORMAT_44_100HZ.sampleRate, /* inputSamples= */ 0L);
|
|
||||||
assertThat(sampleCountAfterProcessorApplied).isEqualTo(0L);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isActive_beforeConfigure_returnsFalse() {
|
public void isActive_beforeConfigure_returnsFalse() {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {1000}, /* speeds= */ new float[] {2f});
|
||||||
/* frameCounts= */ new int[] {1000},
|
|
||||||
/* speeds= */ new float[] {2f});
|
|
||||||
|
|
||||||
SpeedChangingAudioProcessor processor = new SpeedChangingAudioProcessor(speedProvider);
|
SpeedChangingAudioProcessor processor = new SpeedChangingAudioProcessor(speedProvider);
|
||||||
assertThat(processor.isActive()).isFalse();
|
assertThat(processor.isActive()).isFalse();
|
||||||
@ -797,34 +819,18 @@ public class SpeedChangingAudioProcessorTest {
|
|||||||
throws AudioProcessor.UnhandledAudioFormatException {
|
throws AudioProcessor.UnhandledAudioFormatException {
|
||||||
SpeedProvider speedProvider =
|
SpeedProvider speedProvider =
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
TestSpeedProvider.createWithFrameCounts(
|
||||||
AUDIO_FORMAT_44_100HZ,
|
AUDIO_FORMAT, /* frameCounts= */ new int[] {1000}, /* speeds= */ new float[] {2f});
|
||||||
/* frameCounts= */ new int[] {1000},
|
|
||||||
/* speeds= */ new float[] {2f});
|
|
||||||
|
|
||||||
SpeedChangingAudioProcessor processor = new SpeedChangingAudioProcessor(speedProvider);
|
SpeedChangingAudioProcessor processor = new SpeedChangingAudioProcessor(speedProvider);
|
||||||
processor.configure(AUDIO_FORMAT_44_100HZ);
|
processor.configure(AUDIO_FORMAT);
|
||||||
assertThat(processor.isActive()).isTrue();
|
assertThat(processor.isActive()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getInputFrameCountForOutput_withZeroOutputFrames_returnsZero() {
|
|
||||||
SpeedProvider speedProvider =
|
|
||||||
TestSpeedProvider.createWithFrameCounts(
|
|
||||||
AUDIO_FORMAT_44_100HZ,
|
|
||||||
/* frameCounts= */ new int[] {1000, 10000, 8200},
|
|
||||||
/* speeds= */ new float[] {0.2f, 8f, 0.5f});
|
|
||||||
|
|
||||||
long inputFrames =
|
|
||||||
getInputFrameCountForOutput(
|
|
||||||
speedProvider, AUDIO_FORMAT_44_100HZ.sampleRate, /* outputFrameCount= */ 0L);
|
|
||||||
assertThat(inputFrames).isEqualTo(0L);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SpeedChangingAudioProcessor getConfiguredSpeedChangingAudioProcessor(
|
private static SpeedChangingAudioProcessor getConfiguredSpeedChangingAudioProcessor(
|
||||||
SpeedProvider speedProvider) throws AudioProcessor.UnhandledAudioFormatException {
|
SpeedProvider speedProvider) throws AudioProcessor.UnhandledAudioFormatException {
|
||||||
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
new SpeedChangingAudioProcessor(speedProvider);
|
new SpeedChangingAudioProcessor(speedProvider);
|
||||||
speedChangingAudioProcessor.configure(AUDIO_FORMAT_44_100HZ);
|
speedChangingAudioProcessor.configure(AUDIO_FORMAT);
|
||||||
speedChangingAudioProcessor.flush();
|
speedChangingAudioProcessor.flush();
|
||||||
return speedChangingAudioProcessor;
|
return speedChangingAudioProcessor;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user