mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Fix missing error handling durations in HLS
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=208023954
This commit is contained in:
parent
d5c7bff643
commit
c1998da44e
5 changed files with 33 additions and 28 deletions
|
|
@ -32,7 +32,6 @@ import com.google.android.exoplayer2.trackselection.BaseTrackSelection;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy;
|
|
||||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||||
import com.google.android.exoplayer2.util.TimestampAdjuster;
|
import com.google.android.exoplayer2.util.TimestampAdjuster;
|
||||||
import com.google.android.exoplayer2.util.UriUtil;
|
import com.google.android.exoplayer2.util.UriUtil;
|
||||||
|
|
@ -414,10 +413,11 @@ import java.util.List;
|
||||||
* Called when a playlist load encounters an error.
|
* Called when a playlist load encounters an error.
|
||||||
*
|
*
|
||||||
* @param url The url of the playlist whose load encountered an error.
|
* @param url The url of the playlist whose load encountered an error.
|
||||||
* @param shouldBlacklist Whether the playlist should be blacklisted.
|
* @param blacklistDurationMs The duration for which the playlist should be blacklisted. Or {@link
|
||||||
|
* C#TIME_UNSET} if the playlist should not be blacklisted.
|
||||||
* @return True if blacklisting did not encounter errors. False otherwise.
|
* @return True if blacklisting did not encounter errors. False otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean onPlaylistError(HlsUrl url, boolean shouldBlacklist) {
|
public boolean onPlaylistError(HlsUrl url, long blacklistDurationMs) {
|
||||||
int trackGroupIndex = trackGroup.indexOf(url.format);
|
int trackGroupIndex = trackGroup.indexOf(url.format);
|
||||||
if (trackGroupIndex == C.INDEX_UNSET) {
|
if (trackGroupIndex == C.INDEX_UNSET) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -427,9 +427,8 @@ import java.util.List;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
seenExpectedPlaylistError |= expectedPlaylistUrl == url;
|
seenExpectedPlaylistError |= expectedPlaylistUrl == url;
|
||||||
return !shouldBlacklist
|
return blacklistDurationMs == C.TIME_UNSET
|
||||||
|| trackSelection.blacklist(
|
|| trackSelection.blacklist(trackSelectionIndex, blacklistDurationMs);
|
||||||
trackSelectionIndex, DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private methods.
|
// Private methods.
|
||||||
|
|
|
||||||
|
|
@ -330,10 +330,10 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPlaylistError(HlsUrl url, boolean shouldBlacklist) {
|
public boolean onPlaylistError(HlsUrl url, long blacklistDurationMs) {
|
||||||
boolean noBlacklistingFailure = true;
|
boolean noBlacklistingFailure = true;
|
||||||
for (HlsSampleStreamWrapper streamWrapper : sampleStreamWrappers) {
|
for (HlsSampleStreamWrapper streamWrapper : sampleStreamWrappers) {
|
||||||
noBlacklistingFailure &= streamWrapper.onPlaylistError(url, shouldBlacklist);
|
noBlacklistingFailure &= streamWrapper.onPlaylistError(url, blacklistDurationMs);
|
||||||
}
|
}
|
||||||
callback.onContinueLoadingRequested(this);
|
callback.onContinueLoadingRequested(this);
|
||||||
return noBlacklistingFailure;
|
return noBlacklistingFailure;
|
||||||
|
|
|
||||||
|
|
@ -416,8 +416,8 @@ import java.util.List;
|
||||||
chunkSource.setIsTimestampMaster(isTimestampMaster);
|
chunkSource.setIsTimestampMaster(isTimestampMaster);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onPlaylistError(HlsUrl url, boolean shouldBlacklist) {
|
public boolean onPlaylistError(HlsUrl url, long blacklistDurationMs) {
|
||||||
return chunkSource.onPlaylistError(url, shouldBlacklist);
|
return chunkSource.onPlaylistError(url, blacklistDurationMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SampleStream implementation.
|
// SampleStream implementation.
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ import com.google.android.exoplayer2.source.hls.HlsDataSourceFactory;
|
||||||
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl;
|
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl;
|
||||||
import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment;
|
import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy;
|
|
||||||
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||||
import com.google.android.exoplayer2.upstream.Loader;
|
import com.google.android.exoplayer2.upstream.Loader;
|
||||||
import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction;
|
import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction;
|
||||||
|
|
@ -208,7 +207,7 @@ public final class DefaultHlsPlaylistTracker
|
||||||
MediaPlaylistBundle primaryBundle = playlistBundles.get(primaryHlsUrl);
|
MediaPlaylistBundle primaryBundle = playlistBundles.get(primaryHlsUrl);
|
||||||
if (isMediaPlaylist) {
|
if (isMediaPlaylist) {
|
||||||
// We don't need to load the playlist again. We can use the same result.
|
// We don't need to load the playlist again. We can use the same result.
|
||||||
primaryBundle.processLoadedPlaylist((HlsMediaPlaylist) result);
|
primaryBundle.processLoadedPlaylist((HlsMediaPlaylist) result, loadDurationMs);
|
||||||
} else {
|
} else {
|
||||||
primaryBundle.loadPlaylist();
|
primaryBundle.loadPlaylist();
|
||||||
}
|
}
|
||||||
|
|
@ -321,11 +320,11 @@ public final class DefaultHlsPlaylistTracker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean notifyPlaylistError(HlsUrl playlistUrl, boolean shouldBlacklist) {
|
private boolean notifyPlaylistError(HlsUrl playlistUrl, long blacklistDurationMs) {
|
||||||
int listenersSize = listeners.size();
|
int listenersSize = listeners.size();
|
||||||
boolean anyBlacklistingFailed = false;
|
boolean anyBlacklistingFailed = false;
|
||||||
for (int i = 0; i < listenersSize; i++) {
|
for (int i = 0; i < listenersSize; i++) {
|
||||||
anyBlacklistingFailed |= !listeners.get(i).onPlaylistError(playlistUrl, shouldBlacklist);
|
anyBlacklistingFailed |= !listeners.get(i).onPlaylistError(playlistUrl, blacklistDurationMs);
|
||||||
}
|
}
|
||||||
return anyBlacklistingFailed;
|
return anyBlacklistingFailed;
|
||||||
}
|
}
|
||||||
|
|
@ -473,7 +472,7 @@ public final class DefaultHlsPlaylistTracker
|
||||||
ParsingLoadable<HlsPlaylist> loadable, long elapsedRealtimeMs, long loadDurationMs) {
|
ParsingLoadable<HlsPlaylist> loadable, long elapsedRealtimeMs, long loadDurationMs) {
|
||||||
HlsPlaylist result = loadable.getResult();
|
HlsPlaylist result = loadable.getResult();
|
||||||
if (result instanceof HlsMediaPlaylist) {
|
if (result instanceof HlsMediaPlaylist) {
|
||||||
processLoadedPlaylist((HlsMediaPlaylist) result);
|
processLoadedPlaylist((HlsMediaPlaylist) result, loadDurationMs);
|
||||||
eventDispatcher.loadCompleted(
|
eventDispatcher.loadCompleted(
|
||||||
loadable.dataSpec,
|
loadable.dataSpec,
|
||||||
loadable.getUri(),
|
loadable.getUri(),
|
||||||
|
|
@ -516,9 +515,9 @@ public final class DefaultHlsPlaylistTracker
|
||||||
boolean shouldBlacklist = blacklistDurationMs != C.TIME_UNSET;
|
boolean shouldBlacklist = blacklistDurationMs != C.TIME_UNSET;
|
||||||
|
|
||||||
boolean blacklistingFailed =
|
boolean blacklistingFailed =
|
||||||
notifyPlaylistError(playlistUrl, shouldBlacklist) || !shouldBlacklist;
|
notifyPlaylistError(playlistUrl, blacklistDurationMs) || !shouldBlacklist;
|
||||||
if (shouldBlacklist) {
|
if (shouldBlacklist) {
|
||||||
blacklistingFailed |= blacklistPlaylist();
|
blacklistingFailed |= blacklistPlaylist(blacklistDurationMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blacklistingFailed) {
|
if (blacklistingFailed) {
|
||||||
|
|
@ -569,7 +568,7 @@ public final class DefaultHlsPlaylistTracker
|
||||||
elapsedRealtime);
|
elapsedRealtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processLoadedPlaylist(HlsMediaPlaylist loadedPlaylist) {
|
private void processLoadedPlaylist(HlsMediaPlaylist loadedPlaylist, long loadDurationMs) {
|
||||||
// Update the loaded playlist with any inheritable information from the master playlist.
|
// Update the loaded playlist with any inheritable information from the master playlist.
|
||||||
loadedPlaylist = loadedPlaylist.copyWithMasterPlaylistInfo(masterPlaylist);
|
loadedPlaylist = loadedPlaylist.copyWithMasterPlaylistInfo(masterPlaylist);
|
||||||
|
|
||||||
|
|
@ -585,17 +584,22 @@ public final class DefaultHlsPlaylistTracker
|
||||||
if (loadedPlaylist.mediaSequence + loadedPlaylist.segments.size()
|
if (loadedPlaylist.mediaSequence + loadedPlaylist.segments.size()
|
||||||
< playlistSnapshot.mediaSequence) {
|
< playlistSnapshot.mediaSequence) {
|
||||||
// TODO: Allow customization of playlist resets handling.
|
// TODO: Allow customization of playlist resets handling.
|
||||||
// The media sequence jumped backwards. The server has probably reset.
|
// The media sequence jumped backwards. The server has probably reset. We do not try
|
||||||
|
// blacklisting in this case.
|
||||||
playlistError = new PlaylistResetException(playlistUrl.url);
|
playlistError = new PlaylistResetException(playlistUrl.url);
|
||||||
notifyPlaylistError(playlistUrl, false);
|
notifyPlaylistError(playlistUrl, C.TIME_UNSET);
|
||||||
} else if (currentTimeMs - lastSnapshotChangeMs
|
} else if (currentTimeMs - lastSnapshotChangeMs
|
||||||
> C.usToMs(playlistSnapshot.targetDurationUs)
|
> C.usToMs(playlistSnapshot.targetDurationUs)
|
||||||
* PLAYLIST_STUCK_TARGET_DURATION_COEFFICIENT) {
|
* PLAYLIST_STUCK_TARGET_DURATION_COEFFICIENT) {
|
||||||
// TODO: Allow customization of stuck playlists handling.
|
// TODO: Allow customization of stuck playlists handling.
|
||||||
// The playlist seems to be stuck. Blacklist it.
|
|
||||||
playlistError = new PlaylistStuckException(playlistUrl.url);
|
playlistError = new PlaylistStuckException(playlistUrl.url);
|
||||||
notifyPlaylistError(playlistUrl, true);
|
long blacklistDurationMs =
|
||||||
blacklistPlaylist();
|
loadErrorHandlingPolicy.getBlacklistDurationMsFor(
|
||||||
|
C.DATA_TYPE_MANIFEST, loadDurationMs, playlistError, /* errorCount= */ 1);
|
||||||
|
notifyPlaylistError(playlistUrl, blacklistDurationMs);
|
||||||
|
if (blacklistDurationMs != C.TIME_UNSET) {
|
||||||
|
blacklistPlaylist(blacklistDurationMs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Do not allow the playlist to load again within the target duration if we obtained a new
|
// Do not allow the playlist to load again within the target duration if we obtained a new
|
||||||
|
|
@ -617,11 +621,12 @@ public final class DefaultHlsPlaylistTracker
|
||||||
/**
|
/**
|
||||||
* Blacklists the playlist.
|
* Blacklists the playlist.
|
||||||
*
|
*
|
||||||
|
* @param blacklistDurationMs The number of milliseconds for which the playlist should be
|
||||||
|
* blacklisted.
|
||||||
* @return Whether the playlist is the primary, despite being blacklisted.
|
* @return Whether the playlist is the primary, despite being blacklisted.
|
||||||
*/
|
*/
|
||||||
private boolean blacklistPlaylist() {
|
private boolean blacklistPlaylist(long blacklistDurationMs) {
|
||||||
blacklistUntilMs =
|
blacklistUntilMs = SystemClock.elapsedRealtime() + blacklistDurationMs;
|
||||||
SystemClock.elapsedRealtime() + DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS;
|
|
||||||
return primaryHlsUrl == playlistUrl && !maybeSelectNewPrimaryUrl();
|
return primaryHlsUrl == playlistUrl && !maybeSelectNewPrimaryUrl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,10 +59,11 @@ public interface HlsPlaylistTracker {
|
||||||
* Called if an error is encountered while loading a playlist.
|
* Called if an error is encountered while loading a playlist.
|
||||||
*
|
*
|
||||||
* @param url The loaded url that caused the error.
|
* @param url The loaded url that caused the error.
|
||||||
* @param shouldBlacklist Whether the playlist should be blacklisted.
|
* @param blacklistDurationMs The duration for which the playlist should be blacklisted. Or
|
||||||
|
* {@link C#TIME_UNSET} if the playlist should not be blacklisted.
|
||||||
* @return True if blacklisting did not encounter errors. False otherwise.
|
* @return True if blacklisting did not encounter errors. False otherwise.
|
||||||
*/
|
*/
|
||||||
boolean onPlaylistError(HlsUrl url, boolean shouldBlacklist);
|
boolean onPlaylistError(HlsUrl url, long blacklistDurationMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Thrown when a playlist is considered to be stuck due to a server side error. */
|
/** Thrown when a playlist is considered to be stuck due to a server side error. */
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue