Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
a8180491
authored
Jun 02, 2020
by
olly
Committed by
Oliver Woodman
Jun 03, 2020
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Fix position jank after pausing and seeking
Issue: #6901 PiperOrigin-RevId: 314418536
parent
fb011e66
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
47 additions
and
12 deletions
RELEASENOTES.md
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTimestampPoller.java
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrackPositionTracker.java
RELEASENOTES.md
View file @
a8180491
...
@@ -2,6 +2,9 @@
...
@@ -2,6 +2,9 @@
### 2.11.5 (2020-06-03) ###
### 2.11.5 (2020-06-03) ###
*
Improve the smoothness of video playback immediately after starting, seeking
or resuming a playback
(
[
#6901
](
https://github.com/google/ExoPlayer/issues/6901
)
).
*
Add
`SilenceMediaSource.Factory`
to support tags.
*
Add
`SilenceMediaSource.Factory`
to support tags.
*
Enable the configuration of
`SilenceSkippingAudioProcessor`
*
Enable the configuration of
`SilenceSkippingAudioProcessor`
(
[
#6705
](
https://github.com/google/ExoPlayer/issues/6705
)
).
(
[
#6705
](
https://github.com/google/ExoPlayer/issues/6705
)
).
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTimestampPoller.java
View file @
a8180491
...
@@ -37,7 +37,7 @@ import java.lang.annotation.RetentionPolicy;
...
@@ -37,7 +37,7 @@ import java.lang.annotation.RetentionPolicy;
*
*
* <p>If {@link #hasTimestamp()} returns {@code true}, call {@link #getTimestampSystemTimeUs()} to
* <p>If {@link #hasTimestamp()} returns {@code true}, call {@link #getTimestampSystemTimeUs()} to
* get the system time at which the latest timestamp was sampled and {@link
* get the system time at which the latest timestamp was sampled and {@link
* #getTimestampPositionFrames()} to get its position in frames. If {@link #
isTimestampAdvancing
()}
* #getTimestampPositionFrames()} to get its position in frames. If {@link #
hasAdvancingTimestamp
()}
* returns {@code true}, the caller should assume that the timestamp has been increasing in real
* returns {@code true}, the caller should assume that the timestamp has been increasing in real
* time since it was sampled. Otherwise, it may be stationary.
* time since it was sampled. Otherwise, it may be stationary.
*
*
...
@@ -68,7 +68,7 @@ import java.lang.annotation.RetentionPolicy;
...
@@ -68,7 +68,7 @@ import java.lang.annotation.RetentionPolicy;
private
static
final
int
STATE_ERROR
=
4
;
private
static
final
int
STATE_ERROR
=
4
;
/** The polling interval for {@link #STATE_INITIALIZING} and {@link #STATE_TIMESTAMP}. */
/** The polling interval for {@link #STATE_INITIALIZING} and {@link #STATE_TIMESTAMP}. */
private
static
final
int
FAST_POLL_INTERVAL_US
=
5
_000
;
private
static
final
int
FAST_POLL_INTERVAL_US
=
10
_000
;
/**
/**
* The polling interval for {@link #STATE_TIMESTAMP_ADVANCING} and {@link #STATE_NO_TIMESTAMP}.
* The polling interval for {@link #STATE_TIMESTAMP_ADVANCING} and {@link #STATE_NO_TIMESTAMP}.
*/
*/
...
@@ -110,7 +110,7 @@ import java.lang.annotation.RetentionPolicy;
...
@@ -110,7 +110,7 @@ import java.lang.annotation.RetentionPolicy;
* timestamp is available via {@link #getTimestampSystemTimeUs()} and {@link
* timestamp is available via {@link #getTimestampSystemTimeUs()} and {@link
* #getTimestampPositionFrames()}, and the caller should call {@link #acceptTimestamp()} if the
* #getTimestampPositionFrames()}, and the caller should call {@link #acceptTimestamp()} if the
* timestamp was valid, or {@link #rejectTimestamp()} otherwise. The values returned by {@link
* timestamp was valid, or {@link #rejectTimestamp()} otherwise. The values returned by {@link
* #hasTimestamp()} and {@link #
isTimestampAdvancing
()} may be updated.
* #hasTimestamp()} and {@link #
hasAdvancingTimestamp
()} may be updated.
*
*
* @param systemTimeUs The current system time, in microseconds.
* @param systemTimeUs The current system time, in microseconds.
* @return Whether the timestamp was updated.
* @return Whether the timestamp was updated.
...
@@ -200,12 +200,12 @@ import java.lang.annotation.RetentionPolicy;
...
@@ -200,12 +200,12 @@ import java.lang.annotation.RetentionPolicy;
}
}
/**
/**
* Returns whether th
e timestamp appears to be advancing
. If {@code true}, call {@link
* Returns whether th
is instance has an advancing timestamp
. If {@code true}, call {@link
* #getTimestampSystemTimeUs()} and {@link #getTimestampSystemTimeUs()} to access the timestamp. A
* #getTimestampSystemTimeUs()} and {@link #getTimestampSystemTimeUs()} to access the timestamp. A
* current position for the track can be extrapolated based on elapsed real time since the system
* current position for the track can be extrapolated based on elapsed real time since the system
* time at which the timestamp was sampled.
* time at which the timestamp was sampled.
*/
*/
public
boolean
isTimestampAdvancing
()
{
public
boolean
hasAdvancingTimestamp
()
{
return
state
==
STATE_TIMESTAMP_ADVANCING
;
return
state
==
STATE_TIMESTAMP_ADVANCING
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrackPositionTracker.java
View file @
a8180491
...
@@ -123,6 +123,8 @@ import java.lang.reflect.Method;
...
@@ -123,6 +123,8 @@ import java.lang.reflect.Method;
* <p>This is a fail safe that should not be required on correctly functioning devices.
* <p>This is a fail safe that should not be required on correctly functioning devices.
*/
*/
private
static
final
long
MAX_LATENCY_US
=
5
*
C
.
MICROS_PER_SECOND
;
private
static
final
long
MAX_LATENCY_US
=
5
*
C
.
MICROS_PER_SECOND
;
/** The duration of time used to smooth over an adjustment between position sampling modes. */
private
static
final
long
MODE_SWITCH_SMOOTHING_DURATION_US
=
C
.
MICROS_PER_SECOND
;
private
static
final
long
FORCE_RESET_WORKAROUND_TIMEOUT_MS
=
200
;
private
static
final
long
FORCE_RESET_WORKAROUND_TIMEOUT_MS
=
200
;
...
@@ -160,6 +162,15 @@ import java.lang.reflect.Method;
...
@@ -160,6 +162,15 @@ import java.lang.reflect.Method;
private
long
stopPlaybackHeadPosition
;
private
long
stopPlaybackHeadPosition
;
private
long
endPlaybackHeadPosition
;
private
long
endPlaybackHeadPosition
;
// Results from the previous call to getCurrentPositionUs.
private
long
lastPositionUs
;
private
long
lastSystemTimeUs
;
private
boolean
lastSampleUsedGetTimestampMode
;
// Results from the last call to getCurrentPositionUs that used a different sample mode.
private
long
previousModePositionUs
;
private
long
previousModeSystemTimeUs
;
/**
/**
* Creates a new audio track position tracker.
* Creates a new audio track position tracker.
*
*
...
@@ -218,18 +229,16 @@ import java.lang.reflect.Method;
...
@@ -218,18 +229,16 @@ import java.lang.reflect.Method;
// If the device supports it, use the playback timestamp from AudioTrack.getTimestamp.
// If the device supports it, use the playback timestamp from AudioTrack.getTimestamp.
// Otherwise, derive a smoothed position by sampling the track's frame position.
// Otherwise, derive a smoothed position by sampling the track's frame position.
long
systemTimeUs
=
System
.
nanoTime
()
/
1000
;
long
systemTimeUs
=
System
.
nanoTime
()
/
1000
;
long
positionUs
;
AudioTimestampPoller
audioTimestampPoller
=
Assertions
.
checkNotNull
(
this
.
audioTimestampPoller
);
AudioTimestampPoller
audioTimestampPoller
=
Assertions
.
checkNotNull
(
this
.
audioTimestampPoller
);
if
(
audioTimestampPoller
.
hasTimestamp
())
{
boolean
useGetTimestampMode
=
audioTimestampPoller
.
hasAdvancingTimestamp
();
if
(
useGetTimestampMode
)
{
// Calculate the speed-adjusted position using the timestamp (which may be in the future).
// Calculate the speed-adjusted position using the timestamp (which may be in the future).
long
timestampPositionFrames
=
audioTimestampPoller
.
getTimestampPositionFrames
();
long
timestampPositionFrames
=
audioTimestampPoller
.
getTimestampPositionFrames
();
long
timestampPositionUs
=
framesToDurationUs
(
timestampPositionFrames
);
long
timestampPositionUs
=
framesToDurationUs
(
timestampPositionFrames
);
if
(!
audioTimestampPoller
.
isTimestampAdvancing
())
{
return
timestampPositionUs
;
}
long
elapsedSinceTimestampUs
=
systemTimeUs
-
audioTimestampPoller
.
getTimestampSystemTimeUs
();
long
elapsedSinceTimestampUs
=
systemTimeUs
-
audioTimestampPoller
.
getTimestampSystemTimeUs
();
return
timestampPositionUs
+
elapsedSinceTimestampUs
;
positionUs
=
timestampPositionUs
+
elapsedSinceTimestampUs
;
}
else
{
}
else
{
long
positionUs
;
if
(
playheadOffsetCount
==
0
)
{
if
(
playheadOffsetCount
==
0
)
{
// The AudioTrack has started, but we don't have any samples to compute a smoothed position.
// The AudioTrack has started, but we don't have any samples to compute a smoothed position.
positionUs
=
getPlaybackHeadPositionUs
();
positionUs
=
getPlaybackHeadPositionUs
();
...
@@ -242,8 +251,29 @@ import java.lang.reflect.Method;
...
@@ -242,8 +251,29 @@ import java.lang.reflect.Method;
if
(!
sourceEnded
)
{
if
(!
sourceEnded
)
{
positionUs
=
Math
.
max
(
0
,
positionUs
-
latencyUs
);
positionUs
=
Math
.
max
(
0
,
positionUs
-
latencyUs
);
}
}
return
positionUs
;
}
}
if
(
lastSampleUsedGetTimestampMode
!=
useGetTimestampMode
)
{
// We've switched sampling mode.
previousModeSystemTimeUs
=
lastSystemTimeUs
;
previousModePositionUs
=
lastPositionUs
;
}
long
elapsedSincePreviousModeUs
=
systemTimeUs
-
previousModeSystemTimeUs
;
if
(
elapsedSincePreviousModeUs
<
MODE_SWITCH_SMOOTHING_DURATION_US
)
{
// Use a ramp to smooth between the old mode and the new one to avoid introducing a sudden
// jump if the two modes disagree.
long
previousModeProjectedPositionUs
=
previousModePositionUs
+
elapsedSincePreviousModeUs
;
// A ramp consisting of 1000 points distributed over MODE_SWITCH_SMOOTHING_DURATION_US.
long
rampPoint
=
(
elapsedSincePreviousModeUs
*
1000
)
/
MODE_SWITCH_SMOOTHING_DURATION_US
;
positionUs
*=
rampPoint
;
positionUs
+=
(
1000
-
rampPoint
)
*
previousModeProjectedPositionUs
;
positionUs
/=
1000
;
}
lastSystemTimeUs
=
systemTimeUs
;
lastPositionUs
=
positionUs
;
lastSampleUsedGetTimestampMode
=
useGetTimestampMode
;
return
positionUs
;
}
}
/** Starts position tracking. Must be called immediately before {@link AudioTrack#play()}. */
/** Starts position tracking. Must be called immediately before {@link AudioTrack#play()}. */
...
@@ -458,6 +488,8 @@ import java.lang.reflect.Method;
...
@@ -458,6 +488,8 @@ import java.lang.reflect.Method;
playheadOffsetCount
=
0
;
playheadOffsetCount
=
0
;
nextPlayheadOffsetIndex
=
0
;
nextPlayheadOffsetIndex
=
0
;
lastPlayheadSampleTimeUs
=
0
;
lastPlayheadSampleTimeUs
=
0
;
lastSystemTimeUs
=
0
;
previousModeSystemTimeUs
=
0
;
}
}
/**
/**
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment