Skip to content

Commit

Permalink
Prevent unnecessary consecutive playlist loads
Browse files Browse the repository at this point in the history
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=170078933
  • Loading branch information
ojw28 committed Oct 17, 2017
1 parent d8ceef1 commit e7d6f1a
Showing 1 changed file with 43 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -364,9 +364,8 @@ private void createBundles(List<HlsUrl> urls) {
*
* @param url The url of the playlist.
* @param newSnapshot The new snapshot.
* @return True if a refresh should be scheduled.
*/
private boolean onPlaylistUpdated(HlsUrl url, HlsMediaPlaylist newSnapshot) {
private void onPlaylistUpdated(HlsUrl url, HlsMediaPlaylist newSnapshot) {
if (url == primaryHlsUrl) {
if (primaryUrlSnapshot == null) {
// This is the first primary url snapshot.
Expand All @@ -379,8 +378,6 @@ private boolean onPlaylistUpdated(HlsUrl url, HlsMediaPlaylist newSnapshot) {
for (int i = 0; i < listenersSize; i++) {
listeners.get(i).onPlaylistChanged();
}
// If the primary playlist is not the final one, we should schedule a refresh.
return url == primaryHlsUrl && !newSnapshot.hasEndTag;
}

private void notifyPlaylistBlacklisting(HlsUrl url, long blacklistMs) {
Expand Down Expand Up @@ -470,8 +467,9 @@ private final class MediaPlaylistBundle implements Loader.Callback<ParsingLoadab
private HlsMediaPlaylist playlistSnapshot;
private long lastSnapshotLoadMs;
private long lastSnapshotChangeMs;
private long earliestNextLoadTimeMs;
private long blacklistUntilMs;
private boolean pendingRefresh;
private boolean loadPending;
private IOException playlistError;

public MediaPlaylistBundle(HlsUrl playlistUrl) {
Expand Down Expand Up @@ -505,8 +503,16 @@ public void release() {

public void loadPlaylist() {
blacklistUntilMs = 0;
if (!pendingRefresh && !mediaPlaylistLoader.isLoading()) {
mediaPlaylistLoader.startLoading(mediaPlaylistLoadable, this, minRetryCount);
if (loadPending || mediaPlaylistLoader.isLoading()) {
// Load already pending or in progress. Do nothing.
return;
}
long currentTimeMs = SystemClock.elapsedRealtime();
if (currentTimeMs < earliestNextLoadTimeMs) {
loadPending = true;
playlistRefreshHandler.postDelayed(this, earliestNextLoadTimeMs - currentTimeMs);
} else {
loadPlaylistImmediately();
}
}

Expand Down Expand Up @@ -550,8 +556,7 @@ public int onLoadError(ParsingLoadable<HlsPlaylist> loadable, long elapsedRealti
}
boolean shouldRetry = true;
if (ChunkedTrackBlacklistUtil.shouldBlacklist(error)) {
blacklistPlaylist();
shouldRetry = primaryHlsUrl == playlistUrl && !maybeSelectNewPrimaryUrl();
shouldRetry = blacklistPlaylist();
}
return shouldRetry ? Loader.RETRY : Loader.DONT_RETRY;
}
Expand All @@ -560,48 +565,60 @@ public int onLoadError(ParsingLoadable<HlsPlaylist> loadable, long elapsedRealti

@Override
public void run() {
pendingRefresh = false;
loadPlaylist();
loadPending = false;
loadPlaylistImmediately();
}

// Internal methods.

private void loadPlaylistImmediately() {
mediaPlaylistLoader.startLoading(mediaPlaylistLoadable, this, minRetryCount);
}

private void processLoadedPlaylist(HlsMediaPlaylist loadedPlaylist) {
HlsMediaPlaylist oldPlaylist = playlistSnapshot;
long currentTimeMs = SystemClock.elapsedRealtime();
lastSnapshotLoadMs = currentTimeMs;
playlistSnapshot = getLatestPlaylistSnapshot(oldPlaylist, loadedPlaylist);
long refreshDelayUs = C.TIME_UNSET;
if (playlistSnapshot != oldPlaylist) {
playlistError = null;
lastSnapshotChangeMs = currentTimeMs;
if (onPlaylistUpdated(playlistUrl, playlistSnapshot)) {
refreshDelayUs = playlistSnapshot.targetDurationUs;
}
onPlaylistUpdated(playlistUrl, playlistSnapshot);
} else if (!playlistSnapshot.hasEndTag) {
if (currentTimeMs - lastSnapshotChangeMs
if (loadedPlaylist.mediaSequence + loadedPlaylist.segments.size()
< playlistSnapshot.mediaSequence) {
// The media sequence jumped backwards. The server has probably reset.
playlistError = new PlaylistResetException(playlistUrl.url);
} else if (currentTimeMs - lastSnapshotChangeMs
> C.usToMs(playlistSnapshot.targetDurationUs)
* PLAYLIST_STUCK_TARGET_DURATION_COEFFICIENT) {
// The playlist seems to be stuck, we blacklist it.
// The playlist seems to be stuck. Blacklist it.
playlistError = new PlaylistStuckException(playlistUrl.url);
blacklistPlaylist();
} else if (loadedPlaylist.mediaSequence + loadedPlaylist.segments.size()
< playlistSnapshot.mediaSequence) {
// The media sequence has jumped backwards. The server has likely reset.
playlistError = new PlaylistResetException(playlistUrl.url);
}
refreshDelayUs = playlistSnapshot.targetDurationUs / 2;
}
if (refreshDelayUs != C.TIME_UNSET) {
// See HLS spec v20, section 6.3.4 for more information on media playlist refreshing.
pendingRefresh = playlistRefreshHandler.postDelayed(this, C.usToMs(refreshDelayUs));
// Do not allow the playlist to load again within the target duration if we obtained a new
// snapshot, or half the target duration otherwise.
earliestNextLoadTimeMs = currentTimeMs + C.usToMs(playlistSnapshot != oldPlaylist
? playlistSnapshot.targetDurationUs : (playlistSnapshot.targetDurationUs / 2));
// Schedule a load if this is the primary playlist and it doesn't have an end tag. Else the
// next load will be scheduled when refreshPlaylist is called, or when this playlist becomes
// the primary.
if (playlistUrl == primaryHlsUrl && !playlistSnapshot.hasEndTag) {
loadPlaylist();
}
}

private void blacklistPlaylist() {
/**
* Blacklists the playlist.
*
* @return Whether the playlist is the primary, despite being blacklisted.
*/
private boolean blacklistPlaylist() {
blacklistUntilMs = SystemClock.elapsedRealtime()
+ ChunkedTrackBlacklistUtil.DEFAULT_TRACK_BLACKLIST_MS;
notifyPlaylistBlacklisting(playlistUrl, ChunkedTrackBlacklistUtil.DEFAULT_TRACK_BLACKLIST_MS);
return primaryHlsUrl == playlistUrl && !maybeSelectNewPrimaryUrl();
}

}
Expand Down

0 comments on commit e7d6f1a

Please sign in to comment.