/** * Creates a new audio timestamp poller. * * @param audioTrack The audio track that will provide timestamps, if the platform supports it. */ public AudioTimestampPoller(AudioTrack audioTrack) { if (Util.SDK_INT >= 19) { audioTimestamp = new AudioTimestampV19(audioTrack); reset(); } else { audioTimestamp = null; updateState(STATE_NO_TIMESTAMP); } }
private void maybePollAndCheckTimestamp(long systemTimeUs, long playbackPositionUs) { AudioTimestampPoller audioTimestampPoller = Assertions.checkNotNull(this.audioTimestampPoller); if (!audioTimestampPoller.maybePollTimestamp(systemTimeUs)) { return; } // Perform sanity checks on the timestamp and accept/reject it. long audioTimestampSystemTimeUs = audioTimestampPoller.getTimestampSystemTimeUs(); long audioTimestampPositionFrames = audioTimestampPoller.getTimestampPositionFrames(); if (Math.abs(audioTimestampSystemTimeUs - systemTimeUs) > MAX_AUDIO_TIMESTAMP_OFFSET_US) { listener.onSystemTimeUsMismatch( audioTimestampPositionFrames, audioTimestampSystemTimeUs, systemTimeUs, playbackPositionUs); audioTimestampPoller.rejectTimestamp(); } else if (Math.abs(framesToDurationUs(audioTimestampPositionFrames) - playbackPositionUs) > MAX_AUDIO_TIMESTAMP_OFFSET_US) { listener.onPositionFramesMismatch( audioTimestampPositionFrames, audioTimestampSystemTimeUs, systemTimeUs, playbackPositionUs); audioTimestampPoller.rejectTimestamp(); } else { audioTimestampPoller.acceptTimestamp(); } }
if (audioTimestampPoller.hasTimestamp()) { long timestampPositionFrames = audioTimestampPoller.getTimestampPositionFrames(); long timestampPositionUs = framesToDurationUs(timestampPositionFrames); if (!audioTimestampPoller.isTimestampAdvancing()) { return timestampPositionUs; long elapsedSinceTimestampUs = systemTimeUs - audioTimestampPoller.getTimestampSystemTimeUs(); return timestampPositionUs + elapsedSinceTimestampUs; } else {
/** * Accepts the timestamp last polled in {@link #maybePollTimestamp(long)}. If the instance is in * the error state, it will begin to poll timestamps frequently again. */ public void acceptTimestamp() { if (state == STATE_ERROR) { reset(); } }
/** * Rejects the timestamp last polled in {@link #maybePollTimestamp(long)}. The instance will enter * the error state and poll timestamps infrequently until the next call to {@link * #acceptTimestamp()}. */ public void rejectTimestamp() { updateState(STATE_ERROR); }
this.outputPcmFrameSize = outputPcmFrameSize; this.bufferSize = bufferSize; audioTimestampPoller = new AudioTimestampPoller(audioTrack); outputSampleRate = audioTrack.getSampleRate(); needsPassthroughWorkarounds = needsPassthroughWorkarounds(outputEncoding);
/** Starts position tracking. Must be called immediately before {@link AudioTrack#play()}. */ public void start() { Assertions.checkNotNull(audioTimestampPoller).reset(); }
/** Resets polling. Should be called whenever the audio track is paused or resumed. */ public void reset() { if (audioTimestamp != null) { updateState(STATE_INITIALIZING); } }
updateState(STATE_TIMESTAMP); } else { updateState(STATE_NO_TIMESTAMP); long timestampPositionFrames = audioTimestamp.getTimestampPositionFrames(); if (timestampPositionFrames > initialTimestampPositionFrames) { updateState(STATE_TIMESTAMP_ADVANCING); reset(); if (!updatedTimestamp) { reset(); if (updatedTimestamp) { reset();
/** * Pauses the audio track position tracker, returning whether the audio track needs to be paused * to cause playback to pause. If {@code false} is returned the audio track will pause without * further interaction, as the end of stream has been handled. */ public boolean pause() { resetSyncParams(); if (stopTimestampUs == C.TIME_UNSET) { // The audio track is going to be paused, so reset the timestamp poller to ensure it doesn't // supply an advancing position. Assertions.checkNotNull(audioTimestampPoller).reset(); return true; } // We've handled the end of the stream already, so there's no need to pause the track. return false; }