diff --git a/library/common/src/main/java/com/google/android/exoplayer2/util/TimestampAdjuster.java b/library/common/src/main/java/com/google/android/exoplayer2/util/TimestampAdjuster.java index a76cf9b512..a19bc9fd74 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/util/TimestampAdjuster.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/util/TimestampAdjuster.java @@ -53,8 +53,7 @@ public final class TimestampAdjuster { * microseconds, or {@link #DO_NOT_OFFSET} if timestamps should not be offset. */ public TimestampAdjuster(long firstSampleTimestampUs) { - this.firstSampleTimestampUs = firstSampleTimestampUs; - lastSampleTimestampUs = C.TIME_UNSET; + reset(firstSampleTimestampUs); } /** @@ -80,18 +79,18 @@ public final class TimestampAdjuster { * * * @param canInitialize Whether the caller is able to initialize the adjuster, if needed. - * @param startTimeUs The desired first sample timestamp of the caller, in microseconds. Only used - * if {@code canInitialize} is {@code true}. + * @param firstSampleTimestampUs The desired value of the first adjusted sample timestamp in + * microseconds. Only used if {@code canInitialize} is {@code true}. * @throws InterruptedException If the thread is interrupted whilst blocked waiting for * initialization to complete. */ - public synchronized void sharedInitializeOrWait(boolean canInitialize, long startTimeUs) - throws InterruptedException { + public synchronized void sharedInitializeOrWait( + boolean canInitialize, long firstSampleTimestampUs) throws InterruptedException { if (canInitialize && !sharedInitializationStarted) { - firstSampleTimestampUs = startTimeUs; + reset(firstSampleTimestampUs); sharedInitializationStarted = true; } - if (!canInitialize || startTimeUs != firstSampleTimestampUs) { + if (!canInitialize || this.firstSampleTimestampUs != firstSampleTimestampUs) { while (lastSampleTimestampUs == C.TIME_UNSET) { wait(); } @@ -134,7 +133,7 @@ public final class TimestampAdjuster { } /** - * Resets the instance to its initial state. + * Resets the instance. * * @param firstSampleTimestampUs The desired value of the first adjusted sample timestamp after * this reset, in microseconds, or {@link #DO_NOT_OFFSET} if timestamps should not be offset. @@ -142,6 +141,7 @@ public final class TimestampAdjuster { public synchronized void reset(long firstSampleTimestampUs) { this.firstSampleTimestampUs = firstSampleTimestampUs; lastSampleTimestampUs = C.TIME_UNSET; + timestampOffsetUs = 0; sharedInitializationStarted = false; } diff --git a/library/common/src/test/java/com/google/android/exoplayer2/util/TimestampAdjusterTest.java b/library/common/src/test/java/com/google/android/exoplayer2/util/TimestampAdjusterTest.java new file mode 100644 index 0000000000..f509e294ec --- /dev/null +++ b/library/common/src/test/java/com/google/android/exoplayer2/util/TimestampAdjusterTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.util; + +import static com.google.android.exoplayer2.util.TimestampAdjuster.DO_NOT_OFFSET; +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Tests for {@link TimestampAdjuster}. */ +@RunWith(AndroidJUnit4.class) +public class TimestampAdjusterTest { + + @Test + public void adjustSampleTimestamp_fromZero() { + TimestampAdjuster adjuster = new TimestampAdjuster(/* firstSampleTimestampUs= */ 0); + long firstAdjustedTimestampUs = adjuster.adjustSampleTimestamp(/* timeUs= */ 2000); + long secondAdjustedTimestampUs = adjuster.adjustSampleTimestamp(/* timeUs= */ 6000); + + assertThat(firstAdjustedTimestampUs).isEqualTo(0); + assertThat(secondAdjustedTimestampUs).isEqualTo(4000); + } + + @Test + public void adjustSampleTimestamp_fromNonZero() { + TimestampAdjuster adjuster = new TimestampAdjuster(/* firstSampleTimestampUs= */ 1000); + long firstAdjustedTimestampUs = adjuster.adjustSampleTimestamp(/* timeUs= */ 2000); + long secondAdjustedTimestampUs = adjuster.adjustSampleTimestamp(/* timeUs= */ 6000); + + assertThat(firstAdjustedTimestampUs).isEqualTo(1000); + assertThat(secondAdjustedTimestampUs).isEqualTo(5000); + } + + @Test + public void adjustSampleTimestamp_doNotOffset() { + TimestampAdjuster adjuster = new TimestampAdjuster(/* firstSampleTimestampUs= */ DO_NOT_OFFSET); + long firstAdjustedTimestampUs = adjuster.adjustSampleTimestamp(/* timeUs= */ 2000); + long secondAdjustedTimestampUs = adjuster.adjustSampleTimestamp(/* timeUs= */ 6000); + + assertThat(firstAdjustedTimestampUs).isEqualTo(2000); + assertThat(secondAdjustedTimestampUs).isEqualTo(6000); + } + + @Test + public void adjustSampleTimestamp_afterResetToNotOffset() { + TimestampAdjuster adjuster = new TimestampAdjuster(/* firstSampleTimestampUs= */ 0); + // Let the adjuster establish an offset, to make sure that reset really clears it. + adjuster.adjustSampleTimestamp(/* timeUs= */ 1000); + adjuster.reset(/* firstSampleTimestampUs= */ DO_NOT_OFFSET); + long firstAdjustedTimestampUs = adjuster.adjustSampleTimestamp(/* timeUs= */ 2000); + long secondAdjustedTimestampUs = adjuster.adjustSampleTimestamp(/* timeUs= */ 6000); + + assertThat(firstAdjustedTimestampUs).isEqualTo(2000); + assertThat(secondAdjustedTimestampUs).isEqualTo(6000); + } + + @Test + public void adjustSampleTimestamp_afterResetToDifferentStartTime() { + TimestampAdjuster adjuster = new TimestampAdjuster(/* firstSampleTimestampUs= */ 0); + // Let the adjuster establish an offset, to make sure that reset really clears it. + adjuster.adjustSampleTimestamp(/* timeUs= */ 1000); + adjuster.reset(/* firstSampleTimestampUs= */ 5000); + long firstAdjustedTimestampUs = adjuster.adjustSampleTimestamp(/* timeUs= */ 2000); + long secondAdjustedTimestampUs = adjuster.adjustSampleTimestamp(/* timeUs= */ 6000); + + assertThat(firstAdjustedTimestampUs).isEqualTo(5000); + assertThat(secondAdjustedTimestampUs).isEqualTo(9000); + } +}