mirror of
https://github.com/androidx/media.git
synced 2025-05-11 09:39:52 +08:00
Partially revert "Tell LoadControl whether playback can start"
- Renderers becoming ready is asynchronous, so the change wasn't well thought through :(. - This will bring back the possibility of getting stuck in the buffering-but-not-loading anything state. This will need to be addressed in a future CL. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=183646837
This commit is contained in:
parent
d32181e4e9
commit
e26dc3990d
@ -214,8 +214,7 @@ public class DefaultLoadControl implements LoadControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldContinueLoading(
|
public boolean shouldContinueLoading(long bufferedDurationUs, float playbackSpeed) {
|
||||||
boolean canStartPlayback, long bufferedDurationUs, float playbackSpeed) {
|
|
||||||
boolean targetBufferSizeReached = allocator.getTotalBytesAllocated() >= targetBufferSize;
|
boolean targetBufferSizeReached = allocator.getTotalBytesAllocated() >= targetBufferSize;
|
||||||
boolean wasBuffering = isBuffering;
|
boolean wasBuffering = isBuffering;
|
||||||
if (prioritizeTimeOverSizeThresholds) {
|
if (prioritizeTimeOverSizeThresholds) {
|
||||||
@ -230,9 +229,6 @@ public class DefaultLoadControl implements LoadControl {
|
|||||||
&& (bufferedDurationUs < minBufferUs // below low watermark
|
&& (bufferedDurationUs < minBufferUs // below low watermark
|
||||||
|| (bufferedDurationUs <= maxBufferUs && isBuffering)); // between watermarks
|
|| (bufferedDurationUs <= maxBufferUs && isBuffering)); // between watermarks
|
||||||
}
|
}
|
||||||
if (!isBuffering && !canStartPlayback && !targetBufferSizeReached) {
|
|
||||||
isBuffering = true;
|
|
||||||
}
|
|
||||||
if (priorityTaskManager != null && isBuffering != wasBuffering) {
|
if (priorityTaskManager != null && isBuffering != wasBuffering) {
|
||||||
if (isBuffering) {
|
if (isBuffering) {
|
||||||
priorityTaskManager.add(C.PRIORITY_PLAYBACK);
|
priorityTaskManager.add(C.PRIORITY_PLAYBACK);
|
||||||
|
@ -117,8 +117,7 @@ import java.util.Collections;
|
|||||||
private boolean released;
|
private boolean released;
|
||||||
private boolean playWhenReady;
|
private boolean playWhenReady;
|
||||||
private boolean rebuffering;
|
private boolean rebuffering;
|
||||||
private boolean renderersReadyOrEnded;
|
@Player.RepeatMode private int repeatMode;
|
||||||
private @Player.RepeatMode int repeatMode;
|
|
||||||
private boolean shuffleModeEnabled;
|
private boolean shuffleModeEnabled;
|
||||||
|
|
||||||
private int pendingPrepareCount;
|
private int pendingPrepareCount;
|
||||||
@ -554,8 +553,6 @@ import java.util.Collections;
|
|||||||
}
|
}
|
||||||
renderersReadyOrEnded = renderersReadyOrEnded && rendererReadyOrEnded;
|
renderersReadyOrEnded = renderersReadyOrEnded && rendererReadyOrEnded;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.renderersReadyOrEnded = renderersReadyOrEnded;
|
|
||||||
if (!renderersReadyOrEnded) {
|
if (!renderersReadyOrEnded) {
|
||||||
maybeThrowPeriodPrepareError();
|
maybeThrowPeriodPrepareError();
|
||||||
}
|
}
|
||||||
@ -567,25 +564,14 @@ import java.util.Collections;
|
|||||||
&& playingPeriodHolder.info.isFinal) {
|
&& playingPeriodHolder.info.isFinal) {
|
||||||
setState(Player.STATE_ENDED);
|
setState(Player.STATE_ENDED);
|
||||||
stopRenderers();
|
stopRenderers();
|
||||||
} else if (playbackInfo.playbackState == Player.STATE_BUFFERING) {
|
} else if (playbackInfo.playbackState == Player.STATE_BUFFERING
|
||||||
boolean shouldStartPlayback = isReady();
|
&& shouldTransitionToReadyState(renderersReadyOrEnded)) {
|
||||||
if (shouldStartPlayback && playbackInfo.isLoading && enabledRenderers.length != 0) {
|
setState(Player.STATE_READY);
|
||||||
MediaPeriodHolder loadingHolder = queue.getLoadingPeriod();
|
if (playWhenReady) {
|
||||||
long bufferedPositionUs = loadingHolder.getBufferedPositionUs(!loadingHolder.info.isFinal);
|
startRenderers();
|
||||||
shouldStartPlayback =
|
|
||||||
bufferedPositionUs == C.TIME_END_OF_SOURCE
|
|
||||||
|| loadControl.shouldStartPlayback(
|
|
||||||
bufferedPositionUs - loadingHolder.toPeriodTime(rendererPositionUs),
|
|
||||||
mediaClock.getPlaybackParameters().speed,
|
|
||||||
rebuffering);
|
|
||||||
}
|
}
|
||||||
if (shouldStartPlayback) {
|
} else if (playbackInfo.playbackState == Player.STATE_READY
|
||||||
setState(Player.STATE_READY);
|
&& !(enabledRenderers.length == 0 ? isTimelineReady() : renderersReadyOrEnded)) {
|
||||||
if (playWhenReady) {
|
|
||||||
startRenderers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (playbackInfo.playbackState == Player.STATE_READY && !isReady()) {
|
|
||||||
rebuffering = playWhenReady;
|
rebuffering = playWhenReady;
|
||||||
setState(Player.STATE_BUFFERING);
|
setState(Player.STATE_BUFFERING);
|
||||||
stopRenderers();
|
stopRenderers();
|
||||||
@ -694,7 +680,6 @@ import java.util.Collections;
|
|||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
stopRenderers();
|
stopRenderers();
|
||||||
rebuffering = false;
|
rebuffering = false;
|
||||||
renderersReadyOrEnded = false;
|
|
||||||
setState(Player.STATE_BUFFERING);
|
setState(Player.STATE_BUFFERING);
|
||||||
|
|
||||||
// Clear the timeline, but keep the requested period if it is already prepared.
|
// Clear the timeline, but keep the requested period if it is already prepared.
|
||||||
@ -736,8 +721,8 @@ import java.util.Collections;
|
|||||||
return periodPositionUs;
|
return periodPositionUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldKeepPeriodHolder(MediaPeriodId seekPeriodId, long positionUs,
|
private boolean shouldKeepPeriodHolder(
|
||||||
MediaPeriodHolder holder) {
|
MediaPeriodId seekPeriodId, long positionUs, MediaPeriodHolder holder) {
|
||||||
if (seekPeriodId.equals(holder.info.id) && holder.prepared) {
|
if (seekPeriodId.equals(holder.info.id) && holder.prepared) {
|
||||||
playbackInfo.timeline.getPeriod(holder.info.id.periodIndex, period);
|
playbackInfo.timeline.getPeriod(holder.info.id.periodIndex, period);
|
||||||
int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(positionUs);
|
int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(positionUs);
|
||||||
@ -802,7 +787,6 @@ import java.util.Collections;
|
|||||||
boolean releaseMediaSource, boolean resetPosition, boolean resetState) {
|
boolean releaseMediaSource, boolean resetPosition, boolean resetState) {
|
||||||
handler.removeMessages(MSG_DO_SOME_WORK);
|
handler.removeMessages(MSG_DO_SOME_WORK);
|
||||||
rebuffering = false;
|
rebuffering = false;
|
||||||
renderersReadyOrEnded = false;
|
|
||||||
mediaClock.stop();
|
mediaClock.stop();
|
||||||
rendererPositionUs = RENDERER_TIMESTAMP_OFFSET_US;
|
rendererPositionUs = RENDERER_TIMESTAMP_OFFSET_US;
|
||||||
for (Renderer renderer : enabledRenderers) {
|
for (Renderer renderer : enabledRenderers) {
|
||||||
@ -1115,11 +1099,30 @@ import java.util.Collections;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isReady() {
|
private boolean shouldTransitionToReadyState(boolean renderersReadyOrEnded) {
|
||||||
if (enabledRenderers.length != 0) {
|
if (enabledRenderers.length == 0) {
|
||||||
return renderersReadyOrEnded;
|
// If there are no enabled renderers, determine whether we're ready based on the timeline.
|
||||||
|
return isTimelineReady();
|
||||||
}
|
}
|
||||||
// Determine whether we're ready based on the timeline.
|
if (!renderersReadyOrEnded) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!playbackInfo.isLoading) {
|
||||||
|
// Renderers are ready and we're not loading. Transition to ready, since the alternative is
|
||||||
|
// getting stuck waiting for additional media that's not being loaded.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Renderers are ready and we're loading. Ask the LoadControl whether to transition.
|
||||||
|
MediaPeriodHolder loadingHolder = queue.getLoadingPeriod();
|
||||||
|
long bufferedPositionUs = loadingHolder.getBufferedPositionUs(!loadingHolder.info.isFinal);
|
||||||
|
return bufferedPositionUs == C.TIME_END_OF_SOURCE
|
||||||
|
|| loadControl.shouldStartPlayback(
|
||||||
|
bufferedPositionUs - loadingHolder.toPeriodTime(rendererPositionUs),
|
||||||
|
mediaClock.getPlaybackParameters().speed,
|
||||||
|
rebuffering);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTimelineReady() {
|
||||||
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
|
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
|
||||||
long playingPeriodDurationUs = playingPeriodHolder.info.durationUs;
|
long playingPeriodDurationUs = playingPeriodHolder.info.durationUs;
|
||||||
return playingPeriodDurationUs == C.TIME_UNSET
|
return playingPeriodDurationUs == C.TIME_UNSET
|
||||||
@ -1312,8 +1315,8 @@ import java.util.Collections;
|
|||||||
* @return The index in the new timeline of the first subsequent period, or {@link C#INDEX_UNSET}
|
* @return The index in the new timeline of the first subsequent period, or {@link C#INDEX_UNSET}
|
||||||
* if no such period was found.
|
* if no such period was found.
|
||||||
*/
|
*/
|
||||||
private int resolveSubsequentPeriod(int oldPeriodIndex, Timeline oldTimeline,
|
private int resolveSubsequentPeriod(
|
||||||
Timeline newTimeline) {
|
int oldPeriodIndex, Timeline oldTimeline, Timeline newTimeline) {
|
||||||
int newPeriodIndex = C.INDEX_UNSET;
|
int newPeriodIndex = C.INDEX_UNSET;
|
||||||
int maxIterations = oldTimeline.getPeriodCount();
|
int maxIterations = oldTimeline.getPeriodCount();
|
||||||
for (int i = 0; i < maxIterations && newPeriodIndex == C.INDEX_UNSET; i++) {
|
for (int i = 0; i < maxIterations && newPeriodIndex == C.INDEX_UNSET; i++) {
|
||||||
@ -1391,8 +1394,8 @@ import java.util.Collections;
|
|||||||
* Calls {@link Timeline#getPeriodPosition(Timeline.Window, Timeline.Period, int, long)} using the
|
* Calls {@link Timeline#getPeriodPosition(Timeline.Window, Timeline.Period, int, long)} using the
|
||||||
* current timeline.
|
* current timeline.
|
||||||
*/
|
*/
|
||||||
private Pair<Integer, Long> getPeriodPosition(Timeline timeline, int windowIndex,
|
private Pair<Integer, Long> getPeriodPosition(
|
||||||
long windowPositionUs) {
|
Timeline timeline, int windowIndex, long windowPositionUs) {
|
||||||
return timeline.getPeriodPosition(window, period, windowIndex, windowPositionUs);
|
return timeline.getPeriodPosition(window, period, windowIndex, windowPositionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1576,15 +1579,11 @@ import java.util.Collections;
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean canStartPlayback = playbackInfo.playbackState == Player.STATE_READY || isReady();
|
|
||||||
long bufferedDurationUs =
|
long bufferedDurationUs =
|
||||||
nextLoadPositionUs - loadingPeriodHolder.toPeriodTime(rendererPositionUs);
|
nextLoadPositionUs - loadingPeriodHolder.toPeriodTime(rendererPositionUs);
|
||||||
boolean continueLoading =
|
boolean continueLoading =
|
||||||
loadControl.shouldContinueLoading(
|
loadControl.shouldContinueLoading(
|
||||||
canStartPlayback, bufferedDurationUs, mediaClock.getPlaybackParameters().speed);
|
bufferedDurationUs, mediaClock.getPlaybackParameters().speed);
|
||||||
if (!canStartPlayback && !continueLoading) {
|
|
||||||
throw new StuckBufferingException();
|
|
||||||
}
|
|
||||||
setIsLoading(continueLoading);
|
setIsLoading(continueLoading);
|
||||||
if (continueLoading) {
|
if (continueLoading) {
|
||||||
loadingPeriodHolder.continueLoading(rendererPositionUs);
|
loadingPeriodHolder.continueLoading(rendererPositionUs);
|
||||||
@ -1632,8 +1631,9 @@ import java.util.Collections;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enableRenderer(int rendererIndex, boolean wasRendererEnabled,
|
private void enableRenderer(
|
||||||
int enabledRendererIndex) throws ExoPlaybackException {
|
int rendererIndex, boolean wasRendererEnabled, int enabledRendererIndex)
|
||||||
|
throws ExoPlaybackException {
|
||||||
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
|
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
|
||||||
Renderer renderer = renderers[rendererIndex];
|
Renderer renderer = renderers[rendererIndex];
|
||||||
enabledRenderers[enabledRendererIndex] = renderer;
|
enabledRenderers[enabledRendererIndex] = renderer;
|
||||||
|
@ -90,17 +90,11 @@ public interface LoadControl {
|
|||||||
/**
|
/**
|
||||||
* Called by the player to determine whether it should continue to load the source.
|
* Called by the player to determine whether it should continue to load the source.
|
||||||
*
|
*
|
||||||
* @param canStartPlayback Whether the player has the minimum amount of data necessary to start
|
|
||||||
* playback. If {@code false}, this method must return {@code true} or playback will fail.
|
|
||||||
* Hence {@code true} should be returned in this case, unless some hard upper limit (e.g. on
|
|
||||||
* the amount of memory that the control will permit to be allocated) has been exceeded.
|
|
||||||
* Always true if playback is currently started.
|
|
||||||
* @param bufferedDurationUs The duration of media that's currently buffered.
|
* @param bufferedDurationUs The duration of media that's currently buffered.
|
||||||
* @param playbackSpeed The current playback speed.
|
* @param playbackSpeed The current playback speed.
|
||||||
* @return Whether the loading should continue.
|
* @return Whether the loading should continue.
|
||||||
*/
|
*/
|
||||||
boolean shouldContinueLoading(
|
boolean shouldContinueLoading(long bufferedDurationUs, float playbackSpeed);
|
||||||
boolean canStartPlayback, long bufferedDurationUs, float playbackSpeed);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called repeatedly by the player when it's loading the source, has yet to start playback, and
|
* Called repeatedly by the player when it's loading the source, has yet to start playback, and
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2018 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.google.android.exoplayer2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thrown when the player is stuck in a state where it has insufficient media to start playback, but
|
|
||||||
* its {@link LoadControl} is indicating that no further media should be loaded.
|
|
||||||
*/
|
|
||||||
public final class StuckBufferingException extends IllegalStateException {}
|
|
Loading…
x
Reference in New Issue
Block a user