From c1181000f94837b1a70910bf8add6dc33ba6fb36 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 11 Jun 2018 06:32:16 -0700 Subject: [PATCH] Correctly report buffered position for multi-period window. Currently only the buffered position in the current media period can be queried. To achieve this, we save the buffered positions of all MediaPeriods to the PlaybackInfo together with a list of MediaPeriodIds. ExoPlayerImpl can then determine the correct buffered position for multi-period windows and windows with midroll ads. In addition, this change adds two new convenience methods to the Player interface to query the total buffered duration across all windows and to get the buffered duration of the content while playing an ad. Issue:#4023 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=200041791 --- RELEASENOTES.md | 4 + .../exoplayer2/ext/cast/CastPlayer.java | 14 ++ .../android/exoplayer2/ExoPlayerImpl.java | 59 +++-- .../exoplayer2/ExoPlayerImplInternal.java | 40 +++- .../android/exoplayer2/MediaPeriodHolder.java | 3 +- .../android/exoplayer2/PlaybackInfo.java | 211 +++++++++++------- .../com/google/android/exoplayer2/Player.java | 24 +- .../android/exoplayer2/SimpleExoPlayer.java | 10 + .../exoplayer2/ui/PlayerControlView.java | 15 +- .../exoplayer2/testutil/StubExoPlayer.java | 10 + 10 files changed, 274 insertions(+), 116 deletions(-) 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(); + } }