diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 353d2a1fa9..c62fb5c5b1 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -36,8 +36,6 @@ ([#1904](https://github.com/androidx/media/issues/1904)). * DataSource: * Audio: - * Do not bypass `SonicAudioProcessor` when `SpeedChangingAudioProcessor` - is configured with default parameters. * Video: * Rollback of using `MediaCodecAdapter` supplied pixel aspect ratio values when provided while processing `onOutputFormatChanged` diff --git a/libraries/common/src/main/java/androidx/media3/common/audio/SonicAudioProcessor.java b/libraries/common/src/main/java/androidx/media3/common/audio/SonicAudioProcessor.java index a26522505d..030b1e3dff 100644 --- a/libraries/common/src/main/java/androidx/media3/common/audio/SonicAudioProcessor.java +++ b/libraries/common/src/main/java/androidx/media3/common/audio/SonicAudioProcessor.java @@ -15,11 +15,8 @@ */ package androidx.media3.common.audio; -import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkNotNull; -import static java.lang.Math.abs; -import androidx.annotation.FloatRange; import androidx.annotation.Nullable; import androidx.media3.common.C; import androidx.media3.common.Format; @@ -47,8 +44,6 @@ public class SonicAudioProcessor implements AudioProcessor { */ private static final int MIN_BYTES_FOR_DURATION_SCALING_CALCULATION = 1024; - private final boolean shouldBeActiveWithDefaultParameters; - private int pendingOutputSampleRate; private float speed; private float pitch; @@ -69,17 +64,6 @@ public class SonicAudioProcessor implements AudioProcessor { /** Creates a new Sonic audio processor. */ public SonicAudioProcessor() { - this(/* keepActiveWithDefaultParameters= */ false); - } - - /** - * Creates a new instance of {@link SonicAudioProcessor}. - * - *
If {@code keepActiveWithDefaultParameters} is set to {@code true}, then {@link #isActive()} - * returns {@code true} when parameters have been configured to default values that result in - * no-op processing. - */ - /* package */ SonicAudioProcessor(boolean keepActiveWithDefaultParameters) { speed = 1f; pitch = 1f; pendingInputAudioFormat = AudioFormat.NOT_SET; @@ -90,7 +74,6 @@ public class SonicAudioProcessor implements AudioProcessor { shortBuffer = buffer.asShortBuffer(); outputBuffer = EMPTY_BUFFER; pendingOutputSampleRate = SAMPLE_RATE_NO_CHANGE; - shouldBeActiveWithDefaultParameters = keepActiveWithDefaultParameters; } /** @@ -100,8 +83,7 @@ public class SonicAudioProcessor implements AudioProcessor { * * @param speed The target factor by which playback should be sped up. */ - public final void setSpeed(@FloatRange(from = 0f, fromInclusive = false) float speed) { - checkArgument(speed > 0f); + public final void setSpeed(float speed) { if (this.speed != speed) { this.speed = speed; pendingSonicRecreation = true; @@ -115,8 +97,7 @@ public class SonicAudioProcessor implements AudioProcessor { * * @param pitch The target pitch. */ - public final void setPitch(@FloatRange(from = 0f, fromInclusive = false) float pitch) { - checkArgument(pitch > 0f); + public final void setPitch(float pitch) { if (this.pitch != pitch) { this.pitch = pitch; pendingSonicRecreation = true; @@ -132,7 +113,6 @@ public class SonicAudioProcessor implements AudioProcessor { * @see #configure(AudioFormat) */ public final void setOutputSampleRateHz(int sampleRateHz) { - checkArgument(sampleRateHz == SAMPLE_RATE_NO_CHANGE || sampleRateHz > 0); pendingOutputSampleRate = sampleRateHz; } @@ -216,13 +196,9 @@ public class SonicAudioProcessor implements AudioProcessor { @Override public final boolean isActive() { return pendingOutputAudioFormat.sampleRate != Format.NO_VALUE - && (shouldBeActiveWithDefaultParameters || !areParametersSetToDefaultValues()); - } - - private boolean areParametersSetToDefaultValues() { - return abs(speed - 1f) < CLOSE_THRESHOLD - && abs(pitch - 1f) < CLOSE_THRESHOLD - && pendingOutputAudioFormat.sampleRate == pendingInputAudioFormat.sampleRate; + && (Math.abs(speed - 1f) >= CLOSE_THRESHOLD + || Math.abs(pitch - 1f) >= CLOSE_THRESHOLD + || pendingOutputAudioFormat.sampleRate != pendingInputAudioFormat.sampleRate); } @Override 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 e2e1eb8e71..be20fa8024 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 @@ -24,7 +24,6 @@ import static androidx.media3.common.util.Util.sampleCountToDurationUs; import static java.lang.Math.min; import static java.lang.Math.round; -import android.annotation.SuppressLint; import androidx.annotation.GuardedBy; import androidx.annotation.IntRange; import androidx.media3.common.C; @@ -100,8 +99,7 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor { public SpeedChangingAudioProcessor(SpeedProvider speedProvider) { this.speedProvider = speedProvider; lock = new Object(); - sonicAudioProcessor = - new SynchronizedSonicAudioProcessor(lock, /* keepActiveWithDefaultParameters= */ true); + sonicAudioProcessor = new SynchronizedSonicAudioProcessor(lock); pendingCallbackInputTimesUs = new LongArrayQueue(); pendingCallbacks = new ArrayDeque<>(); speedAdjustedTimeAsyncInputTimeUs = C.TIME_UNSET; @@ -176,11 +174,19 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor { } long startPosition = inputBuffer.position(); - sonicAudioProcessor.queueInput(inputBuffer); - if (bytesToNextSpeedChange != C.LENGTH_UNSET - && (inputBuffer.position() - startPosition) == bytesToNextSpeedChange) { - sonicAudioProcessor.queueEndOfStream(); - endOfStreamQueuedToSonic = true; + if (isUsingSonic()) { + sonicAudioProcessor.queueInput(inputBuffer); + if (bytesToNextSpeedChange != C.LENGTH_UNSET + && (inputBuffer.position() - startPosition) == bytesToNextSpeedChange) { + sonicAudioProcessor.queueEndOfStream(); + endOfStreamQueuedToSonic = true; + } + } else { + ByteBuffer buffer = replaceOutputBuffer(/* size= */ inputBuffer.remaining()); + if (inputBuffer.hasRemaining()) { + buffer.put(inputBuffer); + } + buffer.flip(); } long bytesRead = inputBuffer.position() - startPosition; checkState( @@ -198,11 +204,9 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor { } } - // Not using BaseAudioProcessor's buffers. - @SuppressLint("MissingSuperCall") @Override public ByteBuffer getOutput() { - ByteBuffer output = sonicAudioProcessor.getOutput(); + ByteBuffer output = isUsingSonic() ? sonicAudioProcessor.getOutput() : super.getOutput(); processPendingCallbacks(); return output; } @@ -347,8 +351,10 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor { if (newSpeed != currentSpeed) { updateSpeedChangeArrays(timeUs); currentSpeed = newSpeed; - sonicAudioProcessor.setSpeed(newSpeed); - sonicAudioProcessor.setPitch(newSpeed); + if (isUsingSonic()) { + sonicAudioProcessor.setSpeed(newSpeed); + sonicAudioProcessor.setPitch(newSpeed); + } // Invalidate any previously created buffers in SonicAudioProcessor and the base class. sonicAudioProcessor.flush(); endOfStreamQueuedToSonic = false; @@ -372,25 +378,39 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor { } private long getPlayoutDurationUsAtCurrentSpeed(long mediaDurationUs) { - return sonicAudioProcessor.getPlayoutDuration(mediaDurationUs); + return isUsingSonic() + ? sonicAudioProcessor.getPlayoutDuration(mediaDurationUs) + : mediaDurationUs; } private long getMediaDurationUsAtCurrentSpeed(long playoutDurationUs) { - return sonicAudioProcessor.getMediaDuration(playoutDurationUs); + return isUsingSonic() + ? sonicAudioProcessor.getMediaDuration(playoutDurationUs) + : 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; + if (isUsingSonic()) { + // 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; + } else { + lastProcessedInputTimeUs = sampleCountToDurationUs(framesRead, inputAudioFormat.sampleRate); + } + } + } + + private boolean isUsingSonic() { + synchronized (lock) { + return currentSpeed != 1f; } } diff --git a/libraries/common/src/main/java/androidx/media3/common/audio/SynchronizedSonicAudioProcessor.java b/libraries/common/src/main/java/androidx/media3/common/audio/SynchronizedSonicAudioProcessor.java index 78caf65281..cd447b5882 100644 --- a/libraries/common/src/main/java/androidx/media3/common/audio/SynchronizedSonicAudioProcessor.java +++ b/libraries/common/src/main/java/androidx/media3/common/audio/SynchronizedSonicAudioProcessor.java @@ -26,9 +26,9 @@ import java.nio.ByteBuffer; private final Object lock; private final SonicAudioProcessor sonicAudioProcessor; - public SynchronizedSonicAudioProcessor(Object lock, boolean keepActiveWithDefaultParameters) { + public SynchronizedSonicAudioProcessor(Object lock) { this.lock = lock; - sonicAudioProcessor = new SonicAudioProcessor(keepActiveWithDefaultParameters); + sonicAudioProcessor = new SonicAudioProcessor(); } public final void setSpeed(float speed) { diff --git a/libraries/common/src/test/java/androidx/media3/common/audio/SonicAudioProcessorTest.java b/libraries/common/src/test/java/androidx/media3/common/audio/SonicAudioProcessorTest.java index b5581a3a4b..d3a844a849 100644 --- a/libraries/common/src/test/java/androidx/media3/common/audio/SonicAudioProcessorTest.java +++ b/libraries/common/src/test/java/androidx/media3/common/audio/SonicAudioProcessorTest.java @@ -86,19 +86,11 @@ public final class SonicAudioProcessorTest { } @Test - public void isActive_withDefaultParameters_returnsFalse() throws Exception { + public void isNotActiveWithNoChange() throws Exception { sonicAudioProcessor.configure(AUDIO_FORMAT_44100_HZ); assertThat(sonicAudioProcessor.isActive()).isFalse(); } - @Test - public void isActive_keepActiveWithDefaultParameters_returnsTrue() throws Exception { - SonicAudioProcessor processor = - new SonicAudioProcessor(/* keepActiveWithDefaultParameters= */ true); - processor.configure(AUDIO_FORMAT_44100_HZ); - assertThat(processor.isActive()).isTrue(); - } - @Test public void doesNotSupportNon16BitInput() throws Exception { try {