google/ExoPlayer · warning · AudioSink.InvalidAudioTrackTimestampException
Spurious audio timestamp (system clock mismatch): {audioTime
Error message
Spurious audio timestamp (system clock mismatch): {audioTimestampPositionFrames}, {audioTimestampSystemTimeUs}, {systemTimeUs}, {playbackPositionUs}, {submittedFrames}, {writtenFrames} What it means
DefaultAudioSink listens to AudioTimestamp (via AudioTrack.getTimestamp) to keep playback positions accurate. A timestamp frame position that is farther in the future than the frames actually submitted to the track indicates the device's timestamp clock disagrees with the system clock (a known firmware/driver bug). Depending on failOnSpuriousAudioTimestamp (DefaultAudioSink.Builder experimental flag, default false), the sink either logs a warning ('Spurious audio timestamp (system clock mismatch)...') or throws InvalidAudioTrackTimestampException with the same diagnostic tuple: position frames, timestamp system time, current system time, playback position, submitted and written frames.
Source
Thrown at library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java:1994
long audioTimestampPositionFrames,
long audioTimestampSystemTimeUs,
long systemTimeUs,
long playbackPositionUs) {
String message =
"Spurious audio timestamp (system clock mismatch): "
+ audioTimestampPositionFrames
+ ", "
+ audioTimestampSystemTimeUs
+ ", "
+ systemTimeUs
+ ", "
+ playbackPositionUs
+ ", "
+ getSubmittedFrames()
+ ", "
+ getWrittenFrames();
if (failOnSpuriousAudioTimestamp) {
throw new InvalidAudioTrackTimestampException(message);
}
Log.w(TAG, message);
}
@Override
public void onInvalidLatency(long latencyUs) {
Log.w(TAG, "Ignoring impossibly large audio latency: " + latencyUs);
}
@Override
public void onPositionAdvancing(long playoutStartSystemTimeMs) {
if (listener != null) {
listener.onPositionAdvancing(playoutStartSystemTimeMs);
}
}
@Override
public void onUnderrun(int bufferSize, long bufferSizeMs) {View on GitHub (pinned to dd430f7053)
Solutions
- Keep the default behavior (do not call setFailOnSpuriousAudioTimestamp(true)) so mismatches are only logged.
- If you need fail-fast in QA builds, wrap playback in a catch for InvalidAudioTrackTimestampException and recreate the player to resynchronize.
- Report the device model/Android version with the diagnostic tuple — this is a device firmware issue, not app logic.
- Periodically re-sync or restart playback on affected devices when warnings spam the log.
Example fix
// before
new DefaultAudioSink.Builder(ctx)
.setFailOnSpuriousAudioTimestamp(true) // throws on flaky devices
.build();
// after
new DefaultAudioSink.Builder(ctx)
.setFailOnSpuriousAudioTimestamp(false) // default: log-only
.build(); Defensive patterns
Strategy: try-catch
Validate before calling
// before enabling fail-fast behavior, screen known-affected devices boolean riskyDevice = Build.MODEL in AFFECTED_MODELS; sinkBuilder.setFailOnSpuriousAudioTimestamp(!riskyDevice);
Try / catch
try {
player.play();
} catch (Exception e) {
if (e instanceof AudioSink.InvalidAudioTrackTimestampException
|| e.getCause() instanceof AudioSink.InvalidAudioTrackTimestampException) {
recreatePlayerAndSeekTo(player.getCurrentPosition()); // resync timestamps
}
} Prevention
- Leave setFailOnSpuriousAudioTimestamp at default false
- Monitor Logcat for 'Spurious audio timestamp' on new device models
- File device-specific reports with the diagnostic tuple
- Avoid enabling fail-fast flags in production builds
When it happens
Trigger: A device AudioTrack reports a timestamp whose audioTimestampSystemTimeUs implies more audio played than has been written — clock skew or buggy timestamping on certain chipsets — and the app enabled setFailOnSpuriousAudioTimestamp(true) on the sink builder.
Common situations: Bespoke/older firmware or emulators with drifting CLOCK_MONOTONIC vs audio DSP clocks; long playback sessions on affected devices; users enabling the fail-fast experimental flag for test builds; usually benign if left at the default warning behavior.
Related errors
- Invalid output channel config (mode=%s) for: %s
- AudioTrack.STATE_UNINITIALIZED
- audioTrackState != AudioTrack.STATE_INITIALIZED
- Unhandled input format: ${audioFormat}
- Unhandled input format: {audioFormat}
AI-assisted analysis of google/ExoPlayer@dd430f7053 (2026-08-14).
Data as JSON: /api/errors/f7e4c57b6ff7bd29.
Report an issue: GitHub.