Fix resetting TimestampAdjuster with DO_NOT_OFFSET

Prior to this change, an initalized TimestampAdjuster that's then
reset with DO_NOT_OFFSET would incorrectly continue to apply the
offset.

Also add a test case for this issue, and for some other simple use
cases.

#minor-release

PiperOrigin-RevId: 388182645
This commit is contained in:
olly 2021-08-02 11:31:04 +01:00 committed by Christos Tsilopoulos
parent a9fdade9df
commit ff71425dca
2 changed files with 93 additions and 9 deletions

View File

@ -53,8 +53,7 @@ public final class TimestampAdjuster {
* microseconds, or {@link #DO_NOT_OFFSET} if timestamps should not be offset. * microseconds, or {@link #DO_NOT_OFFSET} if timestamps should not be offset.
*/ */
public TimestampAdjuster(long firstSampleTimestampUs) { public TimestampAdjuster(long firstSampleTimestampUs) {
this.firstSampleTimestampUs = firstSampleTimestampUs; reset(firstSampleTimestampUs);
lastSampleTimestampUs = C.TIME_UNSET;
} }
/** /**
@ -80,18 +79,18 @@ public final class TimestampAdjuster {
* </ul> * </ul>
* *
* @param canInitialize Whether the caller is able to initialize the adjuster, if needed. * @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 * @param firstSampleTimestampUs The desired value of the first adjusted sample timestamp in
* if {@code canInitialize} is {@code true}. * microseconds. Only used if {@code canInitialize} is {@code true}.
* @throws InterruptedException If the thread is interrupted whilst blocked waiting for * @throws InterruptedException If the thread is interrupted whilst blocked waiting for
* initialization to complete. * initialization to complete.
*/ */
public synchronized void sharedInitializeOrWait(boolean canInitialize, long startTimeUs) public synchronized void sharedInitializeOrWait(
throws InterruptedException { boolean canInitialize, long firstSampleTimestampUs) throws InterruptedException {
if (canInitialize && !sharedInitializationStarted) { if (canInitialize && !sharedInitializationStarted) {
firstSampleTimestampUs = startTimeUs; reset(firstSampleTimestampUs);
sharedInitializationStarted = true; sharedInitializationStarted = true;
} }
if (!canInitialize || startTimeUs != firstSampleTimestampUs) { if (!canInitialize || this.firstSampleTimestampUs != firstSampleTimestampUs) {
while (lastSampleTimestampUs == C.TIME_UNSET) { while (lastSampleTimestampUs == C.TIME_UNSET) {
wait(); 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 * @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. * 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) { public synchronized void reset(long firstSampleTimestampUs) {
this.firstSampleTimestampUs = firstSampleTimestampUs; this.firstSampleTimestampUs = firstSampleTimestampUs;
lastSampleTimestampUs = C.TIME_UNSET; lastSampleTimestampUs = C.TIME_UNSET;
timestampOffsetUs = 0;
sharedInitializationStarted = false; sharedInitializationStarted = false;
} }

View File

@ -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);
}
}