Commit eb08e1a5 by andrewlewis Committed by Oliver Woodman

Work around AudioTrack Bluetooth connection issue

If connecting a Bluetooth audio device fails, the AudioTrack may be left in a
bad state, where it is not actually playing and its position has jumped back to
zero. Detect and work around this case by resetting the track.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=172600912
parent b8ef1dcc
......@@ -293,8 +293,6 @@ public final class DefaultAudioSink implements AudioSink {
@Override
public long getCurrentPositionUs(boolean sourceEnded) {
// If the device supports it, use the playback timestamp from AudioTrack.getTimestamp.
// Otherwise, derive a smoothed position by sampling the track's frame position.
if (!hasCurrentPositionUs()) {
return CURRENT_POSITION_NOT_SET;
}
......@@ -303,6 +301,8 @@ public final class DefaultAudioSink implements AudioSink {
maybeSampleSyncParams();
}
// If the device supports it, use the playback timestamp from AudioTrack.getTimestamp.
// Otherwise, derive a smoothed position by sampling the track's frame position.
long systemClockUs = System.nanoTime() / 1000;
long positionUs;
if (audioTimestampSet) {
......@@ -638,6 +638,13 @@ public final class DefaultAudioSink implements AudioSink {
inputBuffer = null;
return true;
}
if (audioTrackUtil.needsReset(getWrittenFrames())) {
Log.w(TAG, "Resetting stalled audio track");
reset();
return true;
}
return false;
}
......@@ -1292,6 +1299,8 @@ public final class DefaultAudioSink implements AudioSink {
*/
private static class AudioTrackUtil {
private static final long FORCE_RESET_WORKAROUND_TIMEOUT_MS = 200;
protected AudioTrack audioTrack;
private boolean needsPassthroughWorkaround;
private int sampleRate;
......@@ -1300,6 +1309,7 @@ public final class DefaultAudioSink implements AudioSink {
private long passthroughWorkaroundPauseOffset;
private long stopTimestampUs;
private long forceResetWorkaroundTimeMs;
private long stopPlaybackHeadPosition;
private long endPlaybackHeadPosition;
......@@ -1314,6 +1324,7 @@ public final class DefaultAudioSink implements AudioSink {
this.audioTrack = audioTrack;
this.needsPassthroughWorkaround = needsPassthroughWorkaround;
stopTimestampUs = C.TIME_UNSET;
forceResetWorkaroundTimeMs = C.TIME_UNSET;
lastRawPlaybackHeadPosition = 0;
rawPlaybackHeadWrapCount = 0;
passthroughWorkaroundPauseOffset = 0;
......@@ -1349,6 +1360,17 @@ public final class DefaultAudioSink implements AudioSink {
}
/**
* Returns whether the track is in an invalid state and must be reset.
*
* @see #getPlaybackHeadPosition()
*/
public boolean needsReset(long writtenFrames) {
return forceResetWorkaroundTimeMs != C.TIME_UNSET && writtenFrames > 0
&& SystemClock.elapsedRealtime() - forceResetWorkaroundTimeMs
>= FORCE_RESET_WORKAROUND_TIMEOUT_MS;
}
/**
* {@link AudioTrack#getPlaybackHeadPosition()} returns a value intended to be interpreted as an
* unsigned 32 bit integer, which also wraps around periodically. This method returns the
* playback head position as a long that will only wrap around if the value exceeds
......@@ -1380,6 +1402,24 @@ public final class DefaultAudioSink implements AudioSink {
}
rawPlaybackHeadPosition += passthroughWorkaroundPauseOffset;
}
if (Util.SDK_INT <= 26) {
if (rawPlaybackHeadPosition == 0 && lastRawPlaybackHeadPosition > 0
&& state == PLAYSTATE_PLAYING) {
// If connecting a Bluetooth audio device fails, the AudioTrack may be left in a state
// where its Java API is in the playing state, but the native track is stopped. When this
// happens the playback head position gets stuck at zero. In this case, return the old
// playback head position and force the track to be reset after
// {@link #FORCE_RESET_WORKAROUND_TIMEOUT_MS} has elapsed.
if (forceResetWorkaroundTimeMs == C.TIME_UNSET) {
forceResetWorkaroundTimeMs = SystemClock.elapsedRealtime();
}
return lastRawPlaybackHeadPosition;
} else {
forceResetWorkaroundTimeMs = C.TIME_UNSET;
}
}
if (lastRawPlaybackHeadPosition > rawPlaybackHeadPosition) {
// The value must have wrapped around.
rawPlaybackHeadWrapCount++;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment