mirror of
https://github.com/androidx/media.git
synced 2025-05-08 16:10:38 +08:00
Better management of blacklisted playlists
Added an expiration time field to playlists blacklisted to allow Exoplayer to continue playback when playlists that failed were recovered from a bad state. In live environments, some times occur that primary encoder stop working for a while. In that cases, HLS failover mechanism in the player should detect the situation and “switch” to playlists served by the backup encoder (in case a backup encoder exists). This was well managed before these changes. However, and to ensure a playback experience that can recover itself from temporary issues, we cannot blacklist a playlist forever. When streaming live events using HLS, it is quite typical that the player needs to switch from primary to backup playlists, and from backup to primary ones, from time to time to have playback working when temporary issues in the network/encoder are happening. Most of the issues are recoverable, so what I have implemented is a mechanism that makes blacklisted playlist to be available again after a while (60 seconds). Evaluation of this algorithm should happen just when something fails. If player is working with a backup playlist, it shouldn’t switch to the primary one at least something fail.
This commit is contained in:
parent
6d14fc3330
commit
20a40f5d11
@ -106,6 +106,12 @@ public class HlsChunkSource {
|
|||||||
*/
|
*/
|
||||||
public static final long DEFAULT_MAX_BUFFER_TO_SWITCH_DOWN_MS = 20000;
|
public static final long DEFAULT_MAX_BUFFER_TO_SWITCH_DOWN_MS = 20000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default maximum time a media playlist is blacklisted without
|
||||||
|
* rechecking if it is alive again (because an encoder reset, for example)
|
||||||
|
*/
|
||||||
|
public static final long DEFAULT_MAX_TIME_MEDIA_PLAYLIST_BLACKLISTED_MS = 60000;
|
||||||
|
|
||||||
private static final String TAG = "HlsChunkSource";
|
private static final String TAG = "HlsChunkSource";
|
||||||
private static final String AAC_FILE_EXTENSION = ".aac";
|
private static final String AAC_FILE_EXTENSION = ".aac";
|
||||||
private static final float BANDWIDTH_FRACTION = 0.8f;
|
private static final float BANDWIDTH_FRACTION = 0.8f;
|
||||||
@ -127,6 +133,7 @@ public class HlsChunkSource {
|
|||||||
/* package */ byte[] scratchSpace;
|
/* package */ byte[] scratchSpace;
|
||||||
/* package */ final HlsMediaPlaylist[] mediaPlaylists;
|
/* package */ final HlsMediaPlaylist[] mediaPlaylists;
|
||||||
/* package */ final boolean[] mediaPlaylistBlacklistFlags;
|
/* package */ final boolean[] mediaPlaylistBlacklistFlags;
|
||||||
|
/* package */ final long[] mediaPlaylistBlacklistedTimeMs;
|
||||||
/* package */ final long[] lastMediaPlaylistLoadTimesMs;
|
/* package */ final long[] lastMediaPlaylistLoadTimesMs;
|
||||||
/* package */ boolean live;
|
/* package */ boolean live;
|
||||||
/* package */ long durationUs;
|
/* package */ long durationUs;
|
||||||
@ -182,6 +189,7 @@ public class HlsChunkSource {
|
|||||||
enabledVariants = new Variant[] {new Variant(0, playlistUrl, 0, null, -1, -1)};
|
enabledVariants = new Variant[] {new Variant(0, playlistUrl, 0, null, -1, -1)};
|
||||||
mediaPlaylists = new HlsMediaPlaylist[1];
|
mediaPlaylists = new HlsMediaPlaylist[1];
|
||||||
mediaPlaylistBlacklistFlags = new boolean[1];
|
mediaPlaylistBlacklistFlags = new boolean[1];
|
||||||
|
mediaPlaylistBlacklistedTimeMs = new long[1];
|
||||||
lastMediaPlaylistLoadTimesMs = new long[1];
|
lastMediaPlaylistLoadTimesMs = new long[1];
|
||||||
setMediaPlaylist(0, (HlsMediaPlaylist) playlist);
|
setMediaPlaylist(0, (HlsMediaPlaylist) playlist);
|
||||||
} else {
|
} else {
|
||||||
@ -189,6 +197,7 @@ public class HlsChunkSource {
|
|||||||
enabledVariants = filterVariants((HlsMasterPlaylist) playlist, variantIndices);
|
enabledVariants = filterVariants((HlsMasterPlaylist) playlist, variantIndices);
|
||||||
mediaPlaylists = new HlsMediaPlaylist[enabledVariants.length];
|
mediaPlaylists = new HlsMediaPlaylist[enabledVariants.length];
|
||||||
mediaPlaylistBlacklistFlags = new boolean[enabledVariants.length];
|
mediaPlaylistBlacklistFlags = new boolean[enabledVariants.length];
|
||||||
|
mediaPlaylistBlacklistedTimeMs = new long[enabledVariants.length];
|
||||||
lastMediaPlaylistLoadTimesMs = new long[enabledVariants.length];
|
lastMediaPlaylistLoadTimesMs = new long[enabledVariants.length];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,6 +371,8 @@ public class HlsChunkSource {
|
|||||||
if (responseCode == 404 || responseCode == 410) {
|
if (responseCode == 404 || responseCode == 410) {
|
||||||
MediaPlaylistChunk playlistChunk = (MediaPlaylistChunk) chunk;
|
MediaPlaylistChunk playlistChunk = (MediaPlaylistChunk) chunk;
|
||||||
mediaPlaylistBlacklistFlags[playlistChunk.variantIndex] = true;
|
mediaPlaylistBlacklistFlags[playlistChunk.variantIndex] = true;
|
||||||
|
mediaPlaylistBlacklistedTimeMs[playlistChunk.variantIndex] = SystemClock.elapsedRealtime();
|
||||||
|
evaluatePlaylistBlacklistedTimestamps();
|
||||||
if (!allPlaylistsBlacklisted()) {
|
if (!allPlaylistsBlacklisted()) {
|
||||||
// We've handled the 404/410 by blacklisting the playlist.
|
// We've handled the 404/410 by blacklisting the playlist.
|
||||||
Log.w(TAG, "Blacklisted playlist (" + responseCode + "): "
|
Log.w(TAG, "Blacklisted playlist (" + responseCode + "): "
|
||||||
@ -372,6 +383,7 @@ public class HlsChunkSource {
|
|||||||
Log.w(TAG, "Final playlist not blacklisted (" + responseCode + "): "
|
Log.w(TAG, "Final playlist not blacklisted (" + responseCode + "): "
|
||||||
+ playlistChunk.dataSpec.uri);
|
+ playlistChunk.dataSpec.uri);
|
||||||
mediaPlaylistBlacklistFlags[playlistChunk.variantIndex] = false;
|
mediaPlaylistBlacklistFlags[playlistChunk.variantIndex] = false;
|
||||||
|
mediaPlaylistBlacklistedTimeMs[playlistChunk.variantIndex] = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -541,6 +553,17 @@ public class HlsChunkSource {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void evaluatePlaylistBlacklistedTimestamps()
|
||||||
|
{
|
||||||
|
long currentTime = SystemClock.elapsedRealtime();
|
||||||
|
for (int i = 0; i < mediaPlaylistBlacklistFlags.length; i++) {
|
||||||
|
if (mediaPlaylistBlacklistFlags[i] && currentTime - mediaPlaylistBlacklistedTimeMs[i] > DEFAULT_MAX_TIME_MEDIA_PLAYLIST_BLACKLISTED_MS) {
|
||||||
|
mediaPlaylistBlacklistFlags[i] = false;
|
||||||
|
mediaPlaylistBlacklistedTimeMs[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class MediaPlaylistChunk extends DataChunk {
|
private class MediaPlaylistChunk extends DataChunk {
|
||||||
|
|
||||||
@SuppressWarnings("hiding")
|
@SuppressWarnings("hiding")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user