package androidx.media3.exoplayer.audio; import android.media.AudioTrack; import android.os.SystemClock; import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Util; import io.flutter.embedding.android.KeyboardMap; import java.lang.reflect.Method; /* loaded from: classes2.dex */ final class AudioTrackPositionTracker { private static final long FORCE_RESET_WORKAROUND_TIMEOUT_MS = 200; private static final long MAX_AUDIO_TIMESTAMP_OFFSET_US = 5000000; private static final long MAX_LATENCY_US = 5000000; private static final int MAX_PLAYHEAD_OFFSET_COUNT = 10; private static final int MIN_LATENCY_SAMPLE_INTERVAL_US = 500000; private static final int MIN_PLAYHEAD_OFFSET_SAMPLE_INTERVAL_US = 30000; private static final long MODE_SWITCH_SMOOTHING_DURATION_US = 1000000; private static final int PLAYSTATE_PAUSED = 2; private static final int PLAYSTATE_PLAYING = 3; private static final int PLAYSTATE_STOPPED = 1; private static final long RAW_PLAYBACK_HEAD_POSITION_UPDATE_INTERVAL_MS = 5; private AudioTimestampPoller audioTimestampPoller; private AudioTrack audioTrack; private float audioTrackPlaybackSpeed; private int bufferSize; private long bufferSizeUs; private long endPlaybackHeadPosition; private long forceResetWorkaroundTimeMs; private Method getLatencyMethod; private boolean hasData; private boolean isOutputPcm; private long lastLatencySampleTimeUs; private long lastPlayheadSampleTimeUs; private long lastPositionUs; private long lastRawPlaybackHeadPositionSampleTimeMs; private boolean lastSampleUsedGetTimestampMode; private long lastSystemTimeUs; private long latencyUs; private final Listener listener; private boolean needsPassthroughWorkarounds; private int nextPlayheadOffsetIndex; private boolean notifiedPositionIncreasing; private int outputPcmFrameSize; private int outputSampleRate; private long passthroughWorkaroundPauseOffset; private int playheadOffsetCount; private final long[] playheadOffsets; private long previousModePositionUs; private long previousModeSystemTimeUs; private long rawPlaybackHeadPosition; private long rawPlaybackHeadWrapCount; private long smoothedPlayheadOffsetUs; private long stopPlaybackHeadPosition; private long stopTimestampUs; /* loaded from: classes2.dex */ public interface Listener { void onInvalidLatency(long j); void onPositionAdvancing(long j); void onPositionFramesMismatch(long j, long j2, long j3, long j4); void onSystemTimeUsMismatch(long j, long j2, long j3, long j4); void onUnderrun(int i, long j); } private void resetSyncParams() { this.smoothedPlayheadOffsetUs = 0L; this.playheadOffsetCount = 0; this.nextPlayheadOffsetIndex = 0; this.lastPlayheadSampleTimeUs = 0L; this.lastSystemTimeUs = 0L; this.previousModeSystemTimeUs = 0L; this.notifiedPositionIncreasing = false; } public AudioTrackPositionTracker(Listener listener) { this.listener = (Listener) Assertions.checkNotNull(listener); if (Util.SDK_INT >= 18) { try { this.getLatencyMethod = AudioTrack.class.getMethod("getLatency", null); } catch (NoSuchMethodException unused) { } } this.playheadOffsets = new long[10]; } public void setAudioTrack(AudioTrack audioTrack, boolean z, int i, int i2, int i3) { this.audioTrack = audioTrack; this.outputPcmFrameSize = i2; this.bufferSize = i3; this.audioTimestampPoller = new AudioTimestampPoller(audioTrack); this.outputSampleRate = audioTrack.getSampleRate(); this.needsPassthroughWorkarounds = z && needsPassthroughWorkarounds(i); boolean isEncodingLinearPcm = Util.isEncodingLinearPcm(i); this.isOutputPcm = isEncodingLinearPcm; this.bufferSizeUs = isEncodingLinearPcm ? Util.sampleCountToDurationUs(i3 / i2, this.outputSampleRate) : -9223372036854775807L; this.rawPlaybackHeadPosition = 0L; this.rawPlaybackHeadWrapCount = 0L; this.passthroughWorkaroundPauseOffset = 0L; this.hasData = false; this.stopTimestampUs = -9223372036854775807L; this.forceResetWorkaroundTimeMs = -9223372036854775807L; this.lastLatencySampleTimeUs = 0L; this.latencyUs = 0L; this.audioTrackPlaybackSpeed = 1.0f; } public void setAudioTrackPlaybackSpeed(float f) { this.audioTrackPlaybackSpeed = f; AudioTimestampPoller audioTimestampPoller = this.audioTimestampPoller; if (audioTimestampPoller != null) { audioTimestampPoller.reset(); } resetSyncParams(); } public long getCurrentPositionUs(boolean z) { long mediaDurationForPlayoutDuration; if (((AudioTrack) Assertions.checkNotNull(this.audioTrack)).getPlayState() == 3) { maybeSampleSyncParams(); } long nanoTime = System.nanoTime() / 1000; AudioTimestampPoller audioTimestampPoller = (AudioTimestampPoller) Assertions.checkNotNull(this.audioTimestampPoller); boolean hasAdvancingTimestamp = audioTimestampPoller.hasAdvancingTimestamp(); if (hasAdvancingTimestamp) { mediaDurationForPlayoutDuration = Util.sampleCountToDurationUs(audioTimestampPoller.getTimestampPositionFrames(), this.outputSampleRate) + Util.getMediaDurationForPlayoutDuration(nanoTime - audioTimestampPoller.getTimestampSystemTimeUs(), this.audioTrackPlaybackSpeed); } else { if (this.playheadOffsetCount == 0) { mediaDurationForPlayoutDuration = getPlaybackHeadPositionUs(); } else { mediaDurationForPlayoutDuration = Util.getMediaDurationForPlayoutDuration(this.smoothedPlayheadOffsetUs + nanoTime, this.audioTrackPlaybackSpeed); } if (!z) { mediaDurationForPlayoutDuration = Math.max(0L, mediaDurationForPlayoutDuration - this.latencyUs); } } if (this.lastSampleUsedGetTimestampMode != hasAdvancingTimestamp) { this.previousModeSystemTimeUs = this.lastSystemTimeUs; this.previousModePositionUs = this.lastPositionUs; } long j = nanoTime - this.previousModeSystemTimeUs; if (j < 1000000) { long mediaDurationForPlayoutDuration2 = this.previousModePositionUs + Util.getMediaDurationForPlayoutDuration(j, this.audioTrackPlaybackSpeed); long j2 = (j * 1000) / 1000000; mediaDurationForPlayoutDuration = ((mediaDurationForPlayoutDuration * j2) + ((1000 - j2) * mediaDurationForPlayoutDuration2)) / 1000; } if (!this.notifiedPositionIncreasing) { long j3 = this.lastPositionUs; if (mediaDurationForPlayoutDuration > j3) { this.notifiedPositionIncreasing = true; this.listener.onPositionAdvancing(System.currentTimeMillis() - Util.usToMs(Util.getPlayoutDurationForMediaDuration(Util.usToMs(mediaDurationForPlayoutDuration - j3), this.audioTrackPlaybackSpeed))); } } this.lastSystemTimeUs = nanoTime; this.lastPositionUs = mediaDurationForPlayoutDuration; this.lastSampleUsedGetTimestampMode = hasAdvancingTimestamp; return mediaDurationForPlayoutDuration; } public void start() { ((AudioTimestampPoller) Assertions.checkNotNull(this.audioTimestampPoller)).reset(); } public boolean isPlaying() { return ((AudioTrack) Assertions.checkNotNull(this.audioTrack)).getPlayState() == 3; } public boolean mayHandleBuffer(long j) { int playState = ((AudioTrack) Assertions.checkNotNull(this.audioTrack)).getPlayState(); if (this.needsPassthroughWorkarounds) { if (playState == 2) { this.hasData = false; return false; } if (playState == 1 && getPlaybackHeadPosition() == 0) { return false; } } boolean z = this.hasData; boolean hasPendingData = hasPendingData(j); this.hasData = hasPendingData; if (z && !hasPendingData && playState != 1) { this.listener.onUnderrun(this.bufferSize, Util.usToMs(this.bufferSizeUs)); } return true; } public int getAvailableBufferSize(long j) { return this.bufferSize - ((int) (j - (getPlaybackHeadPosition() * this.outputPcmFrameSize))); } public boolean isStalled(long j) { return this.forceResetWorkaroundTimeMs != -9223372036854775807L && j > 0 && SystemClock.elapsedRealtime() - this.forceResetWorkaroundTimeMs >= FORCE_RESET_WORKAROUND_TIMEOUT_MS; } public void handleEndOfStream(long j) { this.stopPlaybackHeadPosition = getPlaybackHeadPosition(); this.stopTimestampUs = SystemClock.elapsedRealtime() * 1000; this.endPlaybackHeadPosition = j; } public boolean hasPendingData(long j) { return j > Util.durationUsToSampleCount(getCurrentPositionUs(false), this.outputSampleRate) || forceHasPendingData(); } public boolean pause() { resetSyncParams(); if (this.stopTimestampUs != -9223372036854775807L) { return false; } ((AudioTimestampPoller) Assertions.checkNotNull(this.audioTimestampPoller)).reset(); return true; } public void reset() { resetSyncParams(); this.audioTrack = null; this.audioTimestampPoller = null; } private void maybeSampleSyncParams() { long nanoTime = System.nanoTime() / 1000; if (nanoTime - this.lastPlayheadSampleTimeUs >= 30000) { long playbackHeadPositionUs = getPlaybackHeadPositionUs(); if (playbackHeadPositionUs != 0) { this.playheadOffsets[this.nextPlayheadOffsetIndex] = Util.getPlayoutDurationForMediaDuration(playbackHeadPositionUs, this.audioTrackPlaybackSpeed) - nanoTime; this.nextPlayheadOffsetIndex = (this.nextPlayheadOffsetIndex + 1) % 10; int i = this.playheadOffsetCount; if (i < 10) { this.playheadOffsetCount = i + 1; } this.lastPlayheadSampleTimeUs = nanoTime; this.smoothedPlayheadOffsetUs = 0L; int i2 = 0; while (true) { int i3 = this.playheadOffsetCount; if (i2 >= i3) { break; } this.smoothedPlayheadOffsetUs += this.playheadOffsets[i2] / i3; i2++; } } else { return; } } if (this.needsPassthroughWorkarounds) { return; } maybePollAndCheckTimestamp(nanoTime); maybeUpdateLatency(nanoTime); } private void maybePollAndCheckTimestamp(long j) { AudioTimestampPoller audioTimestampPoller = (AudioTimestampPoller) Assertions.checkNotNull(this.audioTimestampPoller); if (audioTimestampPoller.maybePollTimestamp(j)) { long timestampSystemTimeUs = audioTimestampPoller.getTimestampSystemTimeUs(); long timestampPositionFrames = audioTimestampPoller.getTimestampPositionFrames(); long playbackHeadPositionUs = getPlaybackHeadPositionUs(); if (Math.abs(timestampSystemTimeUs - j) > 5000000) { this.listener.onSystemTimeUsMismatch(timestampPositionFrames, timestampSystemTimeUs, j, playbackHeadPositionUs); audioTimestampPoller.rejectTimestamp(); } else if (Math.abs(Util.sampleCountToDurationUs(timestampPositionFrames, this.outputSampleRate) - playbackHeadPositionUs) > 5000000) { this.listener.onPositionFramesMismatch(timestampPositionFrames, timestampSystemTimeUs, j, playbackHeadPositionUs); audioTimestampPoller.rejectTimestamp(); } else { audioTimestampPoller.acceptTimestamp(); } } } private void maybeUpdateLatency(long j) { Method method; if (!this.isOutputPcm || (method = this.getLatencyMethod) == null || j - this.lastLatencySampleTimeUs < 500000) { return; } try { long intValue = (((Integer) Util.castNonNull((Integer) method.invoke(Assertions.checkNotNull(this.audioTrack), new Object[0]))).intValue() * 1000) - this.bufferSizeUs; this.latencyUs = intValue; long max = Math.max(intValue, 0L); this.latencyUs = max; if (max > 5000000) { this.listener.onInvalidLatency(max); this.latencyUs = 0L; } } catch (Exception unused) { this.getLatencyMethod = null; } this.lastLatencySampleTimeUs = j; } private boolean forceHasPendingData() { return this.needsPassthroughWorkarounds && ((AudioTrack) Assertions.checkNotNull(this.audioTrack)).getPlayState() == 2 && getPlaybackHeadPosition() == 0; } private static boolean needsPassthroughWorkarounds(int i) { return Util.SDK_INT < 23 && (i == 5 || i == 6); } private long getPlaybackHeadPositionUs() { return Util.sampleCountToDurationUs(getPlaybackHeadPosition(), this.outputSampleRate); } private long getPlaybackHeadPosition() { long elapsedRealtime = SystemClock.elapsedRealtime(); long j = this.stopTimestampUs; if (j != -9223372036854775807L) { return Math.min(this.endPlaybackHeadPosition, this.stopPlaybackHeadPosition + Util.durationUsToSampleCount(Util.getMediaDurationForPlayoutDuration((elapsedRealtime * 1000) - j, this.audioTrackPlaybackSpeed), this.outputSampleRate)); } if (elapsedRealtime - this.lastRawPlaybackHeadPositionSampleTimeMs >= RAW_PLAYBACK_HEAD_POSITION_UPDATE_INTERVAL_MS) { updateRawPlaybackHeadPosition(elapsedRealtime); this.lastRawPlaybackHeadPositionSampleTimeMs = elapsedRealtime; } return this.rawPlaybackHeadPosition + (this.rawPlaybackHeadWrapCount << 32); } private void updateRawPlaybackHeadPosition(long j) { int playState = ((AudioTrack) Assertions.checkNotNull(this.audioTrack)).getPlayState(); if (playState == 1) { return; } long playbackHeadPosition = r0.getPlaybackHeadPosition() & KeyboardMap.kValueMask; if (this.needsPassthroughWorkarounds) { if (playState == 2 && playbackHeadPosition == 0) { this.passthroughWorkaroundPauseOffset = this.rawPlaybackHeadPosition; } playbackHeadPosition += this.passthroughWorkaroundPauseOffset; } if (Util.SDK_INT <= 29) { if (playbackHeadPosition == 0 && this.rawPlaybackHeadPosition > 0 && playState == 3) { if (this.forceResetWorkaroundTimeMs == -9223372036854775807L) { this.forceResetWorkaroundTimeMs = j; return; } return; } this.forceResetWorkaroundTimeMs = -9223372036854775807L; } if (this.rawPlaybackHeadPosition > playbackHeadPosition) { this.rawPlaybackHeadWrapCount++; } this.rawPlaybackHeadPosition = playbackHeadPosition; } }