mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Require playback to be stuck for a minimum period before failing
PiperOrigin-RevId: 420738165
This commit is contained in:
parent
d7b209a13b
commit
c19d1da6ed
1 changed files with 29 additions and 6 deletions
|
|
@ -175,6 +175,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
* this does not matter for now.
|
* this does not matter for now.
|
||||||
*/
|
*/
|
||||||
private static final long MIN_RENDERER_SLEEP_DURATION_MS = 2000;
|
private static final long MIN_RENDERER_SLEEP_DURATION_MS = 2000;
|
||||||
|
/**
|
||||||
|
* Duration for which the player needs to appear stuck before the playback is failed on the
|
||||||
|
* assumption that no further progress will be made. To appear stuck, the player's renderers must
|
||||||
|
* not be ready, there must be more media available to load, and the LoadControl must be refusing
|
||||||
|
* to load it.
|
||||||
|
*/
|
||||||
|
private static final long PLAYBACK_STUCK_AFTER_MS = 4000;
|
||||||
|
|
||||||
private final Renderer[] renderers;
|
private final Renderer[] renderers;
|
||||||
private final Set<Renderer> renderersToReset;
|
private final Set<Renderer> renderersToReset;
|
||||||
|
|
@ -214,15 +221,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
private boolean foregroundMode;
|
private boolean foregroundMode;
|
||||||
private boolean requestForRendererSleep;
|
private boolean requestForRendererSleep;
|
||||||
private boolean offloadSchedulingEnabled;
|
private boolean offloadSchedulingEnabled;
|
||||||
|
|
||||||
private int enabledRendererCount;
|
private int enabledRendererCount;
|
||||||
@Nullable private SeekPosition pendingInitialSeekPosition;
|
@Nullable private SeekPosition pendingInitialSeekPosition;
|
||||||
private long rendererPositionUs;
|
private long rendererPositionUs;
|
||||||
private int nextPendingMessageIndexHint;
|
private int nextPendingMessageIndexHint;
|
||||||
private boolean deliverPendingMessageAtStartPositionRequired;
|
private boolean deliverPendingMessageAtStartPositionRequired;
|
||||||
@Nullable private ExoPlaybackException pendingRecoverableRendererError;
|
@Nullable private ExoPlaybackException pendingRecoverableRendererError;
|
||||||
|
|
||||||
private long setForegroundModeTimeoutMs;
|
private long setForegroundModeTimeoutMs;
|
||||||
|
private long playbackMaybeBecameStuckAtMs;
|
||||||
|
|
||||||
public ExoPlayerImplInternal(
|
public ExoPlayerImplInternal(
|
||||||
Renderer[] renderers,
|
Renderer[] renderers,
|
||||||
|
|
@ -256,6 +262,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
this.pauseAtEndOfWindow = pauseAtEndOfWindow;
|
this.pauseAtEndOfWindow = pauseAtEndOfWindow;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
|
|
||||||
|
playbackMaybeBecameStuckAtMs = C.TIME_UNSET;
|
||||||
backBufferDurationUs = loadControl.getBackBufferDurationUs();
|
backBufferDurationUs = loadControl.getBackBufferDurationUs();
|
||||||
retainBackBufferFromKeyframe = loadControl.retainBackBufferFromKeyframe();
|
retainBackBufferFromKeyframe = loadControl.retainBackBufferFromKeyframe();
|
||||||
|
|
||||||
|
|
@ -676,6 +683,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
private void setState(int state) {
|
private void setState(int state) {
|
||||||
if (playbackInfo.playbackState != state) {
|
if (playbackInfo.playbackState != state) {
|
||||||
|
if (state != Player.STATE_BUFFERING) {
|
||||||
|
playbackMaybeBecameStuckAtMs = C.TIME_UNSET;
|
||||||
|
}
|
||||||
playbackInfo = playbackInfo.copyWithPlaybackState(state);
|
playbackInfo = playbackInfo.copyWithPlaybackState(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1046,6 +1056,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
stopRenderers();
|
stopRenderers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean playbackMaybeStuck = false;
|
||||||
if (playbackInfo.playbackState == Player.STATE_BUFFERING) {
|
if (playbackInfo.playbackState == Player.STATE_BUFFERING) {
|
||||||
for (int i = 0; i < renderers.length; i++) {
|
for (int i = 0; i < renderers.length; i++) {
|
||||||
if (isRendererEnabled(renderers[i])
|
if (isRendererEnabled(renderers[i])
|
||||||
|
|
@ -1056,12 +1067,24 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
if (!playbackInfo.isLoading
|
if (!playbackInfo.isLoading
|
||||||
&& playbackInfo.totalBufferedDurationUs < 500_000
|
&& playbackInfo.totalBufferedDurationUs < 500_000
|
||||||
&& isLoadingPossible()) {
|
&& isLoadingPossible()) {
|
||||||
// Throw if the LoadControl prevents loading even if the buffer is empty or almost empty. We
|
// The renderers are not ready, there is more media available to load, and the LoadControl
|
||||||
// can't compare against 0 to account for small differences between the renderer position
|
// is refusing to load it (indicated by !playbackInfo.isLoading). This could be because the
|
||||||
// and buffered position in the media at the point where playback gets stuck.
|
// renderers are still transitioning to their ready states, but it could also indicate a
|
||||||
throw new IllegalStateException("Playback stuck buffering and not loading");
|
// stuck playback. The playbackInfo.totalBufferedDurationUs check further isolates the
|
||||||
|
// cause to a lack of media for the renderers to consume, to avoid classifying playbacks as
|
||||||
|
// stuck when they're waiting for other reasons (in particular, loading DRM keys).
|
||||||
|
playbackMaybeStuck = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!playbackMaybeStuck) {
|
||||||
|
playbackMaybeBecameStuckAtMs = C.TIME_UNSET;
|
||||||
|
} else if (playbackMaybeBecameStuckAtMs == C.TIME_UNSET) {
|
||||||
|
playbackMaybeBecameStuckAtMs = clock.elapsedRealtime();
|
||||||
|
} else if (clock.elapsedRealtime() - playbackMaybeBecameStuckAtMs >= PLAYBACK_STUCK_AFTER_MS) {
|
||||||
|
throw new IllegalStateException("Playback stuck buffering and not loading");
|
||||||
|
}
|
||||||
|
|
||||||
if (offloadSchedulingEnabled != playbackInfo.offloadSchedulingEnabled) {
|
if (offloadSchedulingEnabled != playbackInfo.offloadSchedulingEnabled) {
|
||||||
playbackInfo = playbackInfo.copyWithOffloadSchedulingEnabled(offloadSchedulingEnabled);
|
playbackInfo = playbackInfo.copyWithOffloadSchedulingEnabled(offloadSchedulingEnabled);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue