VEX-5798: Implement DRM L1 to L3 fallback (#9)

Add support for L1 to L3 Widevine fallback if playback fails initially.
This commit is contained in:
Armands Malejev 2021-10-13 18:03:29 +03:00 committed by GitHub
parent 2fcc1de626
commit 3bcf2c6061
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -31,6 +31,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl; import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.DefaultRenderersFactory; import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.drm.MediaDrmCallbackException;
import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
@ -134,6 +135,7 @@ class ReactExoplayerView extends FrameLayout implements
private int minLoadRetryCount = 3; private int minLoadRetryCount = 3;
private int maxBitRate = 0; private int maxBitRate = 0;
private long seekTime = C.TIME_UNSET; private long seekTime = C.TIME_UNSET;
private boolean hasDrmFailed = false;
private int minBufferMs = DefaultLoadControl.DEFAULT_MIN_BUFFER_MS; private int minBufferMs = DefaultLoadControl.DEFAULT_MIN_BUFFER_MS;
private int maxBufferMs = DefaultLoadControl.DEFAULT_MAX_BUFFER_MS; private int maxBufferMs = DefaultLoadControl.DEFAULT_MAX_BUFFER_MS;
@ -572,8 +574,13 @@ class ReactExoplayerView extends FrameLayout implements
keyRequestPropertiesArray[i + 1]); keyRequestPropertiesArray[i + 1]);
} }
} }
FrameworkMediaDrm mediaDrm = FrameworkMediaDrm.newInstance(uuid);
if (hasDrmFailed) {
// When DRM fails using L1 we want to switch to L3
mediaDrm.setPropertyString("securityLevel", "L3");
}
return new DefaultDrmSessionManager(uuid, return new DefaultDrmSessionManager(uuid,
FrameworkMediaDrm.newInstance(uuid), drmCallback, null, false, 3); mediaDrm, drmCallback, null, false, 3);
} }
private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessionManager drmSessionManager) { private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessionManager drmSessionManager) {
@ -1029,6 +1036,7 @@ class ReactExoplayerView extends FrameLayout implements
public void onPlayerError(ExoPlaybackException e) { public void onPlayerError(ExoPlaybackException e) {
String errorString = "ExoPlaybackException type : " + e.type; String errorString = "ExoPlaybackException type : " + e.type;
String errorCode = "2001"; // Playback error code 2xxx (2001 - unknown playback exception) String errorCode = "2001"; // Playback error code 2xxx (2001 - unknown playback exception)
boolean needsReInitialization = false;
Exception ex = e; Exception ex = e;
if (e.type == ExoPlaybackException.TYPE_RENDERER) { if (e.type == ExoPlaybackException.TYPE_RENDERER) {
Exception cause = e.getRendererException(); Exception cause = e.getRendererException();
@ -1057,6 +1065,9 @@ class ReactExoplayerView extends FrameLayout implements
} }
} }
else if (e.type == ExoPlaybackException.TYPE_SOURCE) { else if (e.type == ExoPlaybackException.TYPE_SOURCE) {
// Re-initialization improves recovery speed and properly resumes
needsReInitialization = true;
errorString = getResources().getString(R.string.unrecognized_media_format);
Exception cause = e.getSourceException(); Exception cause = e.getSourceException();
if (cause instanceof DefaultDrmSessionManager.MissingSchemeDataException) { if (cause instanceof DefaultDrmSessionManager.MissingSchemeDataException) {
errorCode = "3004"; errorCode = "3004";
@ -1073,6 +1084,14 @@ class ReactExoplayerView extends FrameLayout implements
if (rootCause instanceof MediaDrmCallbackException) { if (rootCause instanceof MediaDrmCallbackException) {
errorCode = "3005"; errorCode = "3005";
errorString = getResources().getString(R.string.unrecognized_media_format); errorString = getResources().getString(R.string.unrecognized_media_format);
if (!hasDrmFailed) {
// When DRM fails to reach the app level certificate server it will fail with a source error so we assume that it is DRM related and try one more time
hasDrmFailed = true;
playerNeedsSource = true;
updateResumePosition();
initializePlayer();
return;
}
} }
} }
} }
@ -1083,6 +1102,9 @@ class ReactExoplayerView extends FrameLayout implements
initializePlayer(); initializePlayer();
} else { } else {
updateResumePosition(); updateResumePosition();
if (needsReInitialization) {
initializePlayer();
}
} }
} }