Cache audio timestamp frame position across track transition reset

Upon track transition of offloaded playback of gapless tracks, the framework will reset the audiotrack frame position. The `AudioTrackPositionTracker`'s `AudioTimestampPoller` must be made to expect the reset and cache accumulated sum of `AudioTimestamp.framePosition`.

#cherrypick

PiperOrigin-RevId: 647294360
This commit is contained in:
michaelkatz 2024-06-27 06:24:25 -07:00 committed by Copybara-Service
parent dcbded0fa9
commit a58e77a5a6
2 changed files with 39 additions and 3 deletions

View File

@ -236,6 +236,16 @@ import java.lang.annotation.Target;
return audioTimestamp != null ? audioTimestamp.getTimestampPositionFrames() : C.INDEX_UNSET;
}
/**
* Sets up the poller to expect a reset in audio track frame position due to an impending track
* transition and reusing of the {@link AudioTrack}.
*/
public void expectTimestampFramePositionReset() {
if (audioTimestamp != null) {
audioTimestamp.expectTimestampFramePositionReset();
}
}
private void updateState(@State int state) {
this.state = state;
switch (state) {
@ -270,6 +280,18 @@ import java.lang.annotation.Target;
private long lastTimestampRawPositionFrames;
private long lastTimestampPositionFrames;
/**
* Whether to expect a raw playback head reset.
*
* <p>When an {@link AudioTrack} is reused during offloaded playback, the {@link
* AudioTimestamp#framePosition} is reset upon track transition. {@link AudioTimestampWrapper}
* must be notified of the impending reset and keep track of total accumulated {@code
* AudioTimestamp.framePosition}.
*/
private boolean expectTimestampFramePositionReset;
private long accumulatedRawTimestampFramePosition;
/**
* Creates a new {@link AudioTimestamp} wrapper.
*
@ -291,12 +313,19 @@ import java.lang.annotation.Target;
if (updated) {
long rawPositionFrames = audioTimestamp.framePosition;
if (lastTimestampRawPositionFrames > rawPositionFrames) {
if (expectTimestampFramePositionReset) {
accumulatedRawTimestampFramePosition += lastTimestampRawPositionFrames;
expectTimestampFramePositionReset = false;
} else {
// The value must have wrapped around.
rawTimestampFramePositionWrapCount++;
}
}
lastTimestampRawPositionFrames = rawPositionFrames;
lastTimestampPositionFrames =
rawPositionFrames + (rawTimestampFramePositionWrapCount << 32);
rawPositionFrames
+ accumulatedRawTimestampFramePosition
+ (rawTimestampFramePositionWrapCount << 32);
}
return updated;
}
@ -308,5 +337,9 @@ import java.lang.annotation.Target;
public long getTimestampPositionFrames() {
return lastTimestampPositionFrames;
}
public void expectTimestampFramePositionReset() {
expectTimestampFramePositionReset = true;
}
}
}

View File

@ -476,6 +476,9 @@ import java.lang.reflect.Method;
*/
public void expectRawPlaybackHeadReset() {
expectRawPlaybackHeadReset = true;
if (audioTimestampPoller != null) {
audioTimestampPoller.expectTimestampFramePositionReset();
}
}
/**