diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 28011c993c..11ebed302f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -21,6 +21,10 @@ * Add method to `BandwidthMeter` to return the `TransferListener` used to gather bandwidth information. * Add callback to `VideoListener` to notify of surface size changes. +* Fix bug when reporting buffered position for multi-period windows and add + two additional convenience methods `Player.getTotalBufferedDuration` and + `Player.getContentBufferedDuration` + ([#4023](https://github.com/google/ExoPlayer/issues/4023)). * Allow apps to register custom MIME types ([#4264](https://github.com/google/ExoPlayer/issues/4264)). diff --git a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java index 84724cbb47..8c0d4b88c0 100644 --- a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java +++ b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java @@ -526,6 +526,15 @@ public final class CastPlayer implements Player { : duration == 0 ? 100 : Util.constrainValue((int) ((position * 100) / duration), 0, 100); } + @Override + public long getTotalBufferedDuration() { + long bufferedPosition = getBufferedPosition(); + long currentPosition = getCurrentPosition(); + return bufferedPosition == C.TIME_UNSET || currentPosition == C.TIME_UNSET + ? 0 + : bufferedPosition - currentPosition; + } + @Override public boolean isCurrentWindowDynamic() { return !currentTimeline.isEmpty() @@ -563,6 +572,11 @@ public final class CastPlayer implements Player { return getCurrentPosition(); } + @Override + public long getContentBufferedPosition() { + return getBufferedPosition(); + } + // Internal methods. public void updateInternalState() { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 9a9577c50a..390f8b59a5 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -470,29 +470,37 @@ import java.util.concurrent.CopyOnWriteArraySet; public long getCurrentPosition() { if (shouldMaskPosition()) { return maskingWindowPositionMs; + } else if (playbackInfo.periodId.isAd()) { + return C.usToMs(playbackInfo.positionUs); } else { - return playbackInfoPositionUsToWindowPositionMs(playbackInfo.positionUs); + return periodPositionUsToWindowPositionMs(playbackInfo.periodId, playbackInfo.positionUs); } } @Override public long getBufferedPosition() { - // TODO - Implement this properly. - if (shouldMaskPosition()) { - return maskingWindowPositionMs; - } else { - return playbackInfoPositionUsToWindowPositionMs(playbackInfo.bufferedPositionUs); + if (isPlayingAd()) { + return playbackInfo.loadingMediaPeriodId.equals(playbackInfo.periodId) + ? C.usToMs(playbackInfo.bufferedPositionUs) + : getDuration(); } + return getContentBufferedPosition(); } @Override public int getBufferedPercentage() { long position = getBufferedPosition(); long duration = getDuration(); - return position == C.TIME_UNSET || duration == C.TIME_UNSET ? 0 + return position == C.TIME_UNSET || duration == C.TIME_UNSET + ? 0 : (duration == 0 ? 100 : Util.constrainValue((int) ((position * 100) / duration), 0, 100)); } + @Override + public long getTotalBufferedDuration() { + return Math.max(0, C.usToMs(playbackInfo.totalBufferedDurationUs)); + } + @Override public boolean isCurrentWindowDynamic() { Timeline timeline = playbackInfo.timeline; @@ -530,6 +538,29 @@ import java.util.concurrent.CopyOnWriteArraySet; } } + @Override + public long getContentBufferedPosition() { + if (shouldMaskPosition()) { + return maskingWindowPositionMs; + } + if (playbackInfo.loadingMediaPeriodId.windowSequenceNumber + != playbackInfo.periodId.windowSequenceNumber) { + return playbackInfo.timeline.getWindow(getCurrentWindowIndex(), window).getDurationMs(); + } + long contentBufferedPositionUs = playbackInfo.bufferedPositionUs; + if (playbackInfo.loadingMediaPeriodId.isAd()) { + Timeline.Period loadingPeriod = + playbackInfo.timeline.getPeriod(playbackInfo.loadingMediaPeriodId.periodIndex, period); + contentBufferedPositionUs = + loadingPeriod.getAdGroupTimeUs(playbackInfo.loadingMediaPeriodId.adGroupIndex); + if (contentBufferedPositionUs == C.TIME_END_OF_SOURCE) { + contentBufferedPositionUs = loadingPeriod.durationUs; + } + } + return periodPositionUsToWindowPositionMs( + playbackInfo.loadingMediaPeriodId, contentBufferedPositionUs); + } + @Override public int getRendererCount() { return renderers.length; @@ -649,7 +680,11 @@ import java.util.concurrent.CopyOnWriteArraySet; playbackState, /* isLoading= */ false, resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups, - resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult); + resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult, + playbackInfo.periodId, + playbackInfo.startPositionUs, + /* totalBufferedDurationUs= */ 0, + playbackInfo.startPositionUs); } private void updatePlaybackInfo( @@ -683,12 +718,10 @@ import java.util.concurrent.CopyOnWriteArraySet; } } - private long playbackInfoPositionUsToWindowPositionMs(long positionUs) { + private long periodPositionUsToWindowPositionMs(MediaPeriodId periodId, long positionUs) { long positionMs = C.usToMs(positionUs); - if (!playbackInfo.periodId.isAd()) { - playbackInfo.timeline.getPeriod(playbackInfo.periodId.periodIndex, period); - positionMs += period.getPositionInWindowMs(); - } + playbackInfo.timeline.getPeriod(periodId.periodIndex, period); + positionMs += period.getPositionInWindowMs(); return positionMs; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 8992868aac..817539bea4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -419,6 +419,7 @@ import java.util.Collections; if (!queue.updateRepeatMode(repeatMode)) { seekToCurrentPosition(/* sendDiscontinuity= */ true); } + updateLoadingMediaPeriodId(); } private void setShuffleModeEnabledInternal(boolean shuffleModeEnabled) @@ -427,6 +428,7 @@ import java.util.Collections; if (!queue.updateShuffleModeEnabled(shuffleModeEnabled)) { seekToCurrentPosition(/* sendDiscontinuity= */ true); } + updateLoadingMediaPeriodId(); } private void seekToCurrentPosition(boolean sendDiscontinuity) throws ExoPlaybackException { @@ -483,11 +485,12 @@ import java.util.Collections; playbackInfo.positionUs = periodPositionUs; } - // Update the buffered position. + // Update the buffered position and total buffered duration. + MediaPeriodHolder loadingPeriod = queue.getLoadingPeriod(); playbackInfo.bufferedPositionUs = - enabledRenderers.length == 0 - ? playingPeriodHolder.info.durationUs - : playingPeriodHolder.getBufferedPositionUs(/* convertEosToDuration= */ true); + loadingPeriod.getBufferedPositionUs(/* convertEosToDuration= */ true); + playbackInfo.totalBufferedDurationUs = + playbackInfo.bufferedPositionUs - loadingPeriod.toPeriodTime(rendererPositionUs); } private void doSomeWork() throws ExoPlaybackException, IOException { @@ -691,6 +694,7 @@ import java.util.Collections; resetRendererPosition(periodPositionUs); } + updateLoadingMediaPeriodId(); handler.sendEmptyMessage(MSG_DO_SOME_WORK); return periodPositionUs; } @@ -785,18 +789,26 @@ import java.util.Collections; pendingMessages.clear(); nextPendingMessageIndex = 0; } + // Set the start position to TIME_UNSET so that a subsequent seek to 0 isn't ignored. + MediaPeriodId mediaPeriodId = + resetPosition ? new MediaPeriodId(getFirstPeriodIndex()) : playbackInfo.periodId; + long startPositionUs = resetPosition ? C.TIME_UNSET : playbackInfo.positionUs; + long contentPositionUs = resetPosition ? C.TIME_UNSET : playbackInfo.contentPositionUs; playbackInfo = new PlaybackInfo( resetState ? Timeline.EMPTY : playbackInfo.timeline, resetState ? null : playbackInfo.manifest, - resetPosition ? new MediaPeriodId(getFirstPeriodIndex()) : playbackInfo.periodId, - // Set the start position to TIME_UNSET so that a subsequent seek to 0 isn't ignored. - resetPosition ? C.TIME_UNSET : playbackInfo.positionUs, - resetPosition ? C.TIME_UNSET : playbackInfo.contentPositionUs, + mediaPeriodId, + startPositionUs, + contentPositionUs, playbackInfo.playbackState, /* isLoading= */ false, resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups, - resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult); + resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult, + mediaPeriodId, + startPositionUs, + /* totalBufferedDurationUs= */ 0, + startPositionUs); if (releaseMediaSource) { if (mediaSource != null) { mediaSource.releaseSource(/* listener= */ this); @@ -1051,6 +1063,7 @@ import java.util.Collections; updateLoadControlTrackSelection(periodHolder.trackGroups, periodHolder.trackSelectorResult); } } + updateLoadingMediaPeriodId(); if (playbackInfo.playbackState != Player.STATE_ENDED) { maybeContinueLoading(); updatePlaybackPositions(); @@ -1249,6 +1262,7 @@ import java.util.Collections; if (!queue.updateQueuedPeriods(playingPeriodId, rendererPositionUs)) { seekToCurrentPosition(/* sendDiscontinuity= */ false); } + updateLoadingMediaPeriodId(); } private void handleSourceInfoRefreshEndedPlayback() { @@ -1494,6 +1508,7 @@ import java.util.Collections; info); mediaPeriod.prepare(this, info.startPositionUs); setIsLoading(true); + updateLoadingMediaPeriodId(); } } } @@ -1620,6 +1635,13 @@ import java.util.Collections; && renderer.hasReadStreamToEnd(); } + private void updateLoadingMediaPeriodId() { + MediaPeriodHolder loadingMediaPeriodHolder = queue.getLoadingPeriod(); + MediaPeriodId loadingMediaPeriodId = + loadingMediaPeriodHolder == null ? playbackInfo.periodId : loadingMediaPeriodHolder.info.id; + playbackInfo = playbackInfo.copyWithLoadingMediaPeriodId(loadingMediaPeriodId); + } + @NonNull private static Format[] getFormats(TrackSelection newSelection) { // Build an array of formats contained by the selection. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodHolder.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodHolder.java index 2f71d0d547..c4d69b7e7a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodHolder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodHolder.java @@ -127,7 +127,8 @@ import com.google.android.exoplayer2.util.Assertions; if (!prepared) { return info.startPositionUs; } - long bufferedPositionUs = mediaPeriod.getBufferedPositionUs(); + long bufferedPositionUs = + hasEnabledTracks ? mediaPeriod.getBufferedPositionUs() : C.TIME_END_OF_SOURCE; return bufferedPositionUs == C.TIME_END_OF_SOURCE && convertEosToDuration ? info.durationUs : bufferedPositionUs; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java index 80de073e2d..d79f0538ae 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java @@ -25,18 +25,49 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; */ /* package */ final class PlaybackInfo { + /** The current {@link Timeline}. */ public final Timeline timeline; + /** The current manifest. */ public final @Nullable Object manifest; + /** The {@link MediaPeriodId} of the currently playing media period in the {@link #timeline}. */ public final MediaPeriodId periodId; + /** + * The start position at which playback started in {@link #periodId} relative to the start of the + * associated period in the {@link #timeline}, in microseconds. + */ public final long startPositionUs; + /** + * If {@link #periodId} refers to an ad, the position of the suspended content relative to the + * start of the associated period in the {@link #timeline}, in microseconds. {@link C#TIME_UNSET} + * if {@link #periodId} does not refer to an ad. + */ public final long contentPositionUs; + /** The current playback state. One of the {@link Player}.STATE_ constants. */ public final int playbackState; + /** Whether the player is currently loading. */ public final boolean isLoading; + /** The currently available track groups. */ public final TrackGroupArray trackGroups; + /** The result of the current track selection. */ public final TrackSelectorResult trackSelectorResult; + /** The {@link MediaPeriodId} of the currently loading media period in the {@link #timeline}. */ + public final MediaPeriodId loadingMediaPeriodId; - public volatile long positionUs; + /** + * Position up to which media is buffered in {@link #loadingMediaPeriodId) relative to the start + * of the associated period in the {@link #timeline}, in microseconds. + */ public volatile long bufferedPositionUs; + /** + * Total duration of buffered media from {@link #positionUs} to {@link #bufferedPositionUs} + * including all ads. + */ + public volatile long totalBufferedDurationUs; + /** + * Current playback position in {@link #periodId} relative to the start of the associated period + * in the {@link #timeline}, in microseconds. + */ + public volatile long positionUs; public PlaybackInfo( Timeline timeline, @@ -52,7 +83,11 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; Player.STATE_IDLE, /* isLoading= */ false, trackGroups, - trackSelectorResult); + trackSelectorResult, + new MediaPeriodId(/* periodIndex= */ 0), + startPositionUs, + /* totalBufferedDurationUs= */ 0, + startPositionUs); } public PlaybackInfo( @@ -64,18 +99,24 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; int playbackState, boolean isLoading, TrackGroupArray trackGroups, - TrackSelectorResult trackSelectorResult) { + TrackSelectorResult trackSelectorResult, + MediaPeriodId loadingMediaPeriodId, + long bufferedPositionUs, + long totalBufferedDurationUs, + long positionUs) { this.timeline = timeline; this.manifest = manifest; this.periodId = periodId; this.startPositionUs = startPositionUs; this.contentPositionUs = contentPositionUs; - this.positionUs = startPositionUs; - this.bufferedPositionUs = startPositionUs; this.playbackState = playbackState; this.isLoading = isLoading; this.trackGroups = trackGroups; this.trackSelectorResult = trackSelectorResult; + this.loadingMediaPeriodId = loadingMediaPeriodId; + this.bufferedPositionUs = bufferedPositionUs; + this.totalBufferedDurationUs = totalBufferedDurationUs; + this.positionUs = positionUs; } public PlaybackInfo fromNewPosition( @@ -89,93 +130,113 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; playbackState, isLoading, trackGroups, - trackSelectorResult); + trackSelectorResult, + periodId, + startPositionUs, + /* totalBufferedDurationUs= */ 0, + startPositionUs); } public PlaybackInfo copyWithPeriodIndex(int periodIndex) { - PlaybackInfo playbackInfo = - new PlaybackInfo( - timeline, - manifest, - periodId.copyWithPeriodIndex(periodIndex), - startPositionUs, - contentPositionUs, - playbackState, - isLoading, - trackGroups, - trackSelectorResult); - copyMutablePositions(this, playbackInfo); - return playbackInfo; + return new PlaybackInfo( + timeline, + manifest, + periodId.copyWithPeriodIndex(periodIndex), + startPositionUs, + contentPositionUs, + playbackState, + isLoading, + trackGroups, + trackSelectorResult, + loadingMediaPeriodId, + bufferedPositionUs, + totalBufferedDurationUs, + positionUs); } public PlaybackInfo copyWithTimeline(Timeline timeline, Object manifest) { - PlaybackInfo playbackInfo = - new PlaybackInfo( - timeline, - manifest, - periodId, - startPositionUs, - contentPositionUs, - playbackState, - isLoading, - trackGroups, - trackSelectorResult); - copyMutablePositions(this, playbackInfo); - return playbackInfo; + return new PlaybackInfo( + timeline, + manifest, + periodId, + startPositionUs, + contentPositionUs, + playbackState, + isLoading, + trackGroups, + trackSelectorResult, + loadingMediaPeriodId, + bufferedPositionUs, + totalBufferedDurationUs, + positionUs); } public PlaybackInfo copyWithPlaybackState(int playbackState) { - PlaybackInfo playbackInfo = - new PlaybackInfo( - timeline, - manifest, - periodId, - startPositionUs, - contentPositionUs, - playbackState, - isLoading, - trackGroups, - trackSelectorResult); - copyMutablePositions(this, playbackInfo); - return playbackInfo; + return new PlaybackInfo( + timeline, + manifest, + periodId, + startPositionUs, + contentPositionUs, + playbackState, + isLoading, + trackGroups, + trackSelectorResult, + loadingMediaPeriodId, + bufferedPositionUs, + totalBufferedDurationUs, + positionUs); } public PlaybackInfo copyWithIsLoading(boolean isLoading) { - PlaybackInfo playbackInfo = - new PlaybackInfo( - timeline, - manifest, - periodId, - startPositionUs, - contentPositionUs, - playbackState, - isLoading, - trackGroups, - trackSelectorResult); - copyMutablePositions(this, playbackInfo); - return playbackInfo; + return new PlaybackInfo( + timeline, + manifest, + periodId, + startPositionUs, + contentPositionUs, + playbackState, + isLoading, + trackGroups, + trackSelectorResult, + loadingMediaPeriodId, + bufferedPositionUs, + totalBufferedDurationUs, + positionUs); } public PlaybackInfo copyWithTrackInfo( TrackGroupArray trackGroups, TrackSelectorResult trackSelectorResult) { - PlaybackInfo playbackInfo = - new PlaybackInfo( - timeline, - manifest, - periodId, - startPositionUs, - contentPositionUs, - playbackState, - isLoading, - trackGroups, - trackSelectorResult); - copyMutablePositions(this, playbackInfo); - return playbackInfo; + return new PlaybackInfo( + timeline, + manifest, + periodId, + startPositionUs, + contentPositionUs, + playbackState, + isLoading, + trackGroups, + trackSelectorResult, + loadingMediaPeriodId, + bufferedPositionUs, + totalBufferedDurationUs, + positionUs); } - private static void copyMutablePositions(PlaybackInfo from, PlaybackInfo to) { - to.positionUs = from.positionUs; - to.bufferedPositionUs = from.bufferedPositionUs; + public PlaybackInfo copyWithLoadingMediaPeriodId(MediaPeriodId loadingMediaPeriodId) { + return new PlaybackInfo( + timeline, + manifest, + periodId, + startPositionUs, + contentPositionUs, + playbackState, + isLoading, + trackGroups, + trackSelectorResult, + loadingMediaPeriodId, + bufferedPositionUs, + totalBufferedDurationUs, + positionUs); } - } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Player.java b/library/core/src/main/java/com/google/android/exoplayer2/Player.java index 3075c9273c..995691d163 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Player.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Player.java @@ -678,23 +678,27 @@ public interface Player { */ long getDuration(); - /** - * Returns the playback position in the current window, in milliseconds. - */ + /** Returns the playback position in the current content window or ad, in milliseconds. */ long getCurrentPosition(); /** - * Returns an estimate of the position in the current window up to which data is buffered, in - * milliseconds. + * Returns an estimate of the position in the current content window or ad up to which data is + * buffered, in milliseconds. */ long getBufferedPosition(); /** - * Returns an estimate of the percentage in the current window up to which data is buffered, or 0 - * if no estimate is available. + * Returns an estimate of the percentage in the current content window or ad up to which data is + * buffered, or 0 if no estimate is available. */ int getBufferedPercentage(); + /** + * Returns an estimate of the total buffered duration from the current position, in milliseconds. + * This includes pre-buffered data for subsequent ads and windows. + */ + long getTotalBufferedDuration(); + /** * Returns whether the current window is dynamic, or {@code false} if the {@link Timeline} is * empty. @@ -735,4 +739,10 @@ public interface Player { */ long getContentPosition(); + /** + * If {@link #isPlayingAd()} returns {@code true}, returns an estimate of the content position in + * the current content window up to which data is buffered, in milliseconds. If there is no ad + * playing, the returned position is the same as that returned by {@link #getBufferedPosition()}. + */ + long getContentBufferedPosition(); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 3e4a3c3e11..7fa13338ad 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -905,6 +905,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player return player.getBufferedPercentage(); } + @Override + public long getTotalBufferedDuration() { + return player.getTotalBufferedDuration(); + } + @Override public boolean isCurrentWindowDynamic() { return player.isCurrentWindowDynamic(); @@ -935,6 +940,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player return player.getContentPosition(); } + @Override + public long getContentBufferedPosition() { + return player.getContentBufferedPosition(); + } + // Internal methods. /** diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java index 63c791d166..9ee4862d77 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java @@ -715,7 +715,7 @@ public class PlayerControlView extends FrameLayout { long bufferedPosition = 0; long duration = 0; if (player != null) { - long currentWindowTimeBarOffsetUs = 0; + long currentWindowTimeBarOffsetMs = 0; long durationUs = 0; int adGroupCount = 0; Timeline timeline = player.getCurrentTimeline(); @@ -726,7 +726,7 @@ public class PlayerControlView extends FrameLayout { multiWindowTimeBar ? timeline.getWindowCount() - 1 : currentWindowIndex; for (int i = firstWindowIndex; i <= lastWindowIndex; i++) { if (i == currentWindowIndex) { - currentWindowTimeBarOffsetUs = durationUs; + currentWindowTimeBarOffsetMs = C.usToMs(durationUs); } timeline.getWindow(i, window); if (window.durationUs == C.TIME_UNSET) { @@ -762,15 +762,8 @@ public class PlayerControlView extends FrameLayout { } } duration = C.usToMs(durationUs); - position = C.usToMs(currentWindowTimeBarOffsetUs); - bufferedPosition = position; - if (player.isPlayingAd()) { - position += player.getContentPosition(); - bufferedPosition = position; - } else { - position += player.getCurrentPosition(); - bufferedPosition += player.getBufferedPosition(); - } + position = currentWindowTimeBarOffsetMs + player.getContentPosition(); + bufferedPosition = currentWindowTimeBarOffsetMs + player.getContentBufferedPosition(); if (timeBar != null) { int extraAdGroupCount = extraAdGroupTimesMs.length; int totalAdGroupCount = adGroupCount + extraAdGroupCount; diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java b/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java index d81cef9d8a..b8ad949f4a 100644 --- a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java +++ b/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java @@ -254,6 +254,11 @@ public abstract class StubExoPlayer implements ExoPlayer { throw new UnsupportedOperationException(); } + @Override + public long getTotalBufferedDuration() { + throw new UnsupportedOperationException(); + } + @Override public boolean isCurrentWindowDynamic() { throw new UnsupportedOperationException(); @@ -283,4 +288,9 @@ public abstract class StubExoPlayer implements ExoPlayer { public long getContentPosition() { throw new UnsupportedOperationException(); } + + @Override + public long getContentBufferedPosition() { + throw new UnsupportedOperationException(); + } }