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 e61c689233..a7ee6eb86e 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 @@ -1262,6 +1262,8 @@ import java.util.concurrent.atomic.AtomicBoolean; // Stale event. return; } + playbackInfoUpdate.incrementPendingOperationAcks(pendingPrepareCount); + pendingPrepareCount = 0; Timeline oldTimeline = playbackInfo.timeline; Timeline timeline = sourceRefreshInfo.timeline; @@ -1270,119 +1272,75 @@ import java.util.concurrent.atomic.AtomicBoolean; playbackInfo = playbackInfo.copyWithTimeline(timeline, manifest); resolvePendingMessagePositions(); - if (pendingPrepareCount > 0) { - playbackInfoUpdate.incrementPendingOperationAcks(pendingPrepareCount); - pendingPrepareCount = 0; - if (pendingInitialSeekPosition != null) { - Pair periodPosition = - resolveSeekPosition(pendingInitialSeekPosition, /* trySubsequentPeriods= */ true); - pendingInitialSeekPosition = null; - if (periodPosition == null) { - // The seek position was valid for the timeline that it was performed into, but the - // timeline has changed and a suitable seek position could not be resolved in the new one. - handleSourceInfoRefreshEndedPlayback(); - } else { - Object periodUid = periodPosition.first; - long positionUs = periodPosition.second; - MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(periodUid, positionUs); - playbackInfo = - playbackInfo.resetToNewPosition( - periodId, periodId.isAd() ? 0 : positionUs, /* contentPositionUs= */ positionUs); - } - } else if (playbackInfo.startPositionUs == C.TIME_UNSET) { - if (timeline.isEmpty()) { - handleSourceInfoRefreshEndedPlayback(); - } else { - Pair defaultPosition = - getPeriodPosition( - timeline, timeline.getFirstWindowIndex(shuffleModeEnabled), C.TIME_UNSET); - Object periodUid = defaultPosition.first; - long startPositionUs = defaultPosition.second; - MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(periodUid, startPositionUs); - playbackInfo = - playbackInfo.resetToNewPosition( - periodId, - periodId.isAd() ? 0 : startPositionUs, - /* contentPositionUs= */ startPositionUs); - } + MediaPeriodId newPeriodId = playbackInfo.periodId; + long oldContentPositionUs = + playbackInfo.periodId.isAd() ? playbackInfo.contentPositionUs : playbackInfo.positionUs; + long newContentPositionUs = oldContentPositionUs; + if (pendingInitialSeekPosition != null) { + // Resolve initial seek position. + Pair periodPosition = + resolveSeekPosition(pendingInitialSeekPosition, /* trySubsequentPeriods= */ true); + pendingInitialSeekPosition = null; + if (periodPosition == null) { + // The seek position was valid for the timeline that it was performed into, but the + // timeline has changed and a suitable seek position could not be resolved in the new one. + handleSourceInfoRefreshEndedPlayback(); + return; } - return; - } - - if (oldTimeline.isEmpty()) { - // If the old timeline is empty, the period queue is also empty. - if (!timeline.isEmpty()) { - Pair defaultPosition = - getPeriodPosition( - timeline, timeline.getFirstWindowIndex(shuffleModeEnabled), C.TIME_UNSET); - Object periodUid = defaultPosition.first; - long startPositionUs = defaultPosition.second; - MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(periodUid, startPositionUs); - playbackInfo = - playbackInfo.resetToNewPosition( - periodId, - /* startPositionUs= */ periodId.isAd() ? 0 : startPositionUs, - /* contentPositionUs= */ startPositionUs); - } - return; - } - MediaPeriodHolder periodHolder = queue.getFrontPeriod(); - long contentPositionUs = playbackInfo.contentPositionUs; - Object playingPeriodUid = - periodHolder == null ? playbackInfo.periodId.periodUid : periodHolder.uid; - int periodIndex = timeline.getIndexOfPeriod(playingPeriodUid); - if (periodIndex == C.INDEX_UNSET) { - // We didn't find the current period in the new timeline. Attempt to resolve a subsequent - // period whose window we can restart from. - Object newPeriodUid = resolveSubsequentPeriod(playingPeriodUid, oldTimeline, timeline); + newContentPositionUs = periodPosition.second; + newPeriodId = queue.resolveMediaPeriodIdForAds(periodPosition.first, newContentPositionUs); + } else if (oldContentPositionUs == C.TIME_UNSET && !timeline.isEmpty()) { + // Resolve unset start position to default position. + Pair defaultPosition = + getPeriodPosition( + timeline, timeline.getFirstWindowIndex(shuffleModeEnabled), C.TIME_UNSET); + newContentPositionUs = defaultPosition.second; + newPeriodId = queue.resolveMediaPeriodIdForAds(defaultPosition.first, newContentPositionUs); + } else if (timeline.getIndexOfPeriod(newPeriodId.periodUid) == C.INDEX_UNSET) { + // The current period isn't in the new timeline. Attempt to resolve a subsequent period whose + // window we can restart from. + Object newPeriodUid = resolveSubsequentPeriod(newPeriodId.periodUid, oldTimeline, timeline); if (newPeriodUid == null) { // We failed to resolve a suitable restart position. handleSourceInfoRefreshEndedPlayback(); return; } - // We resolved a subsequent period. Seek to the default position in the corresponding window. + // We resolved a subsequent period. Start at the default position in the corresponding window. Pair defaultPosition = getPeriodPosition( timeline, timeline.getPeriodByUid(newPeriodUid, period).windowIndex, C.TIME_UNSET); - newPeriodUid = defaultPosition.first; - contentPositionUs = defaultPosition.second; - MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(newPeriodUid, contentPositionUs); + newContentPositionUs = defaultPosition.second; + newPeriodId = queue.resolveMediaPeriodIdForAds(defaultPosition.first, newContentPositionUs); + } else if (newPeriodId.isAd()) { + // Recheck if the current ad still needs to be played. + newPeriodId = queue.resolveMediaPeriodIdForAds(newPeriodId.periodUid, newContentPositionUs); + } + + if (playbackInfo.periodId.equals(newPeriodId) && oldContentPositionUs == newContentPositionUs) { + // We can keep the current playing period. Update the rest of the queued periods. + if (!queue.updateQueuedPeriods(rendererPositionUs, getMaxRendererReadPositionUs())) { + seekToCurrentPosition(/* sendDiscontinuity= */ false); + } + handleLoadingMediaPeriodChanged(/* loadingTrackSelectionChanged= */ false); + } else { + // Something changed. Seek to new start position. + MediaPeriodHolder periodHolder = queue.getFrontPeriod(); if (periodHolder != null) { // Update the new playing media period info if it already exists. while (periodHolder.getNext() != null) { periodHolder = periodHolder.getNext(); - if (periodHolder.info.id.equals(periodId)) { + if (periodHolder.info.id.equals(newPeriodId)) { periodHolder.info = queue.getUpdatedMediaPeriodInfo(periodHolder.info); } } } // Actually do the seek. - long seekPositionUs = seekToPeriodPosition(periodId, periodId.isAd() ? 0 : contentPositionUs); + long newPositionUs = newPeriodId.isAd() ? 0 : newContentPositionUs; + long seekedToPositionUs = seekToPeriodPosition(newPeriodId, newPositionUs); playbackInfo = playbackInfo.copyWithNewPosition( - periodId, seekPositionUs, contentPositionUs, getTotalBufferedDurationUs()); - return; + newPeriodId, seekedToPositionUs, newContentPositionUs, getTotalBufferedDurationUs()); } - - MediaPeriodId playingPeriodId = playbackInfo.periodId; - if (playingPeriodId.isAd()) { - MediaPeriodId periodId = - queue.resolveMediaPeriodIdForAds(playingPeriodUid, contentPositionUs); - if (!periodId.equals(playingPeriodId)) { - // The previously playing ad should no longer be played, so skip it. - long seekPositionUs = - seekToPeriodPosition(periodId, periodId.isAd() ? 0 : contentPositionUs); - playbackInfo = - playbackInfo.copyWithNewPosition( - periodId, seekPositionUs, contentPositionUs, getTotalBufferedDurationUs()); - return; - } - } - - if (!queue.updateQueuedPeriods(rendererPositionUs, getMaxRendererReadPositionUs())) { - seekToCurrentPosition(/* sendDiscontinuity= */ false); - } - handleLoadingMediaPeriodChanged(/* loadingTrackSelectionChanged= */ false); } private long getMaxRendererReadPositionUs() {