VEX-4579: Network loss handling (#5)
Add support for customizing back buffer duration and handle network errors gracefully to prevent releasing the player when network is lost.
This commit is contained in:
parent
f6cce0d819
commit
80873102a4
14
README.md
14
README.md
@ -276,10 +276,12 @@ var styles = StyleSheet.create({
|
||||
* [allowsExternalPlayback](#allowsexternalplayback)
|
||||
* [audioOnly](#audioonly)
|
||||
* [automaticallyWaitsToMinimizeStalling](#automaticallyWaitsToMinimizeStalling)
|
||||
* [backBufferDurationMs](#backBufferDurationMs)
|
||||
* [bufferConfig](#bufferconfig)
|
||||
* [controls](#controls)
|
||||
* [currentPlaybackTime](#currentPlaybackTime)
|
||||
* [disableFocus](#disableFocus)
|
||||
* [disableDisconnectError](#disableDisconnectError)
|
||||
* [filter](#filter)
|
||||
* [filterEnabled](#filterEnabled)
|
||||
* [fullscreen](#fullscreen)
|
||||
@ -367,6 +369,11 @@ A Boolean value that indicates whether the player should automatically delay pla
|
||||
|
||||
Platforms: iOS
|
||||
|
||||
#### backBufferDurationMs
|
||||
The number of milliseconds of buffer to keep before the current position. This allows rewinding without rebuffering within that duration.
|
||||
|
||||
Platforms: Android ExoPlayer
|
||||
|
||||
#### bufferConfig
|
||||
Adjust the buffer settings. This prop takes an object with one or more of the properties listed below.
|
||||
|
||||
@ -416,6 +423,13 @@ Determines whether video audio should override background music/audio in Android
|
||||
|
||||
Platforms: Android Exoplayer
|
||||
|
||||
#### disableDisconnectError
|
||||
Determines if the player needs to throw an error when connection is lost or not
|
||||
* **false (default)** - Player will throw an error when connection is lost
|
||||
* **true** - Player will keep trying to buffer when network connect is lost
|
||||
|
||||
Platforms: Android Exoplayer
|
||||
|
||||
### DRM
|
||||
To setup DRM please follow [this guide](./DRM.md)
|
||||
|
||||
|
@ -9,16 +9,28 @@ import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||
public class DefaultReactExoplayerConfig implements ReactExoplayerConfig {
|
||||
|
||||
private final DefaultBandwidthMeter bandwidthMeter;
|
||||
private boolean disableDisconnectError = false;
|
||||
|
||||
public DefaultReactExoplayerConfig(Context context) {
|
||||
this.bandwidthMeter = new DefaultBandwidthMeter.Builder(context).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoadErrorHandlingPolicy buildLoadErrorHandlingPolicy(int minLoadRetryCount) {
|
||||
if (this.disableDisconnectError) {
|
||||
// Use custom error handling policy to prevent throwing an error when losing network connection
|
||||
return new ReactExoplayerLoadErrorHandlingPolicy(minLoadRetryCount);
|
||||
}
|
||||
return new DefaultLoadErrorHandlingPolicy(minLoadRetryCount);
|
||||
}
|
||||
|
||||
public void setDisableDisconnectError(boolean disableDisconnectError) {
|
||||
this.disableDisconnectError = disableDisconnectError;
|
||||
}
|
||||
|
||||
public boolean getDisableDisconnectError() {
|
||||
return this.disableDisconnectError;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultBandwidthMeter getBandwidthMeter() {
|
||||
return bandwidthMeter;
|
||||
|
@ -9,5 +9,8 @@ import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||
public interface ReactExoplayerConfig {
|
||||
LoadErrorHandlingPolicy buildLoadErrorHandlingPolicy(int minLoadRetryCount);
|
||||
|
||||
void setDisableDisconnectError(boolean disableDisconnectError);
|
||||
boolean getDisableDisconnectError();
|
||||
|
||||
DefaultBandwidthMeter getBandwidthMeter();
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
package com.brentvatne.exoplayer;
|
||||
|
||||
import java.io.IOException;
|
||||
import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource.HttpDataSourceException;
|
||||
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy.LoadErrorInfo;
|
||||
import com.google.android.exoplayer2.C;
|
||||
|
||||
public final class ReactExoplayerLoadErrorHandlingPolicy extends DefaultLoadErrorHandlingPolicy {
|
||||
private int minLoadRetryCount = Integer.MAX_VALUE;
|
||||
|
||||
public ReactExoplayerLoadErrorHandlingPolicy(int minLoadRetryCount) {
|
||||
super(minLoadRetryCount);
|
||||
this.minLoadRetryCount = minLoadRetryCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRetryDelayMsFor(LoadErrorInfo loadErrorInfo) {
|
||||
if (loadErrorInfo.exception instanceof HttpDataSourceException) {
|
||||
// Capture the error we get when there is no network connectivity and keep retrying it
|
||||
return 1000; // Retry every second
|
||||
} else if(loadErrorInfo.errorCount < this.minLoadRetryCount) {
|
||||
return Math.min((loadErrorInfo.errorCount - 1) * 1000, 5000); // Default timeout handling
|
||||
} else {
|
||||
return C.TIME_UNSET; // Done retrying and will return the error immediately
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimumLoadableRetryCount(int dataType) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
@ -139,6 +139,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
private Handler mainHandler;
|
||||
|
||||
// Props from React
|
||||
private int backBufferDurationMs = DefaultLoadControl.DEFAULT_BACK_BUFFER_DURATION_MS;
|
||||
private Uri srcUri;
|
||||
private String extension;
|
||||
private boolean repeat;
|
||||
@ -151,6 +152,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
private ReadableArray textTracks;
|
||||
private boolean disableFocus;
|
||||
private boolean disableBuffering;
|
||||
private boolean disableDisconnectError;
|
||||
private boolean preventsDisplaySleepDuringVideoPlayback = true;
|
||||
private float mProgressUpdateInterval = 250.0f;
|
||||
private boolean playInBackground = false;
|
||||
@ -434,7 +436,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
bufferForPlaybackAfterRebufferMs,
|
||||
-1,
|
||||
true,
|
||||
DefaultLoadControl.DEFAULT_BACK_BUFFER_DURATION_MS,
|
||||
backBufferDurationMs,
|
||||
DefaultLoadControl.DEFAULT_RETAIN_BACK_BUFFER_FROM_KEYFRAME
|
||||
);
|
||||
DefaultRenderersFactory renderersFactory =
|
||||
@ -527,6 +529,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessionManager drmSessionManager) {
|
||||
int type = Util.inferContentType(!TextUtils.isEmpty(overrideExtension) ? "." + overrideExtension
|
||||
: uri.getLastPathSegment());
|
||||
config.setDisableDisconnectError(this.disableDisconnectError);
|
||||
switch (type) {
|
||||
case C.TYPE_SS:
|
||||
return new SsMediaSource.Factory(
|
||||
@ -1312,10 +1315,18 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
this.disableFocus = disableFocus;
|
||||
}
|
||||
|
||||
public void setBackBufferDurationMs(int backBufferDurationMs) {
|
||||
this.backBufferDurationMs = backBufferDurationMs;
|
||||
}
|
||||
|
||||
public void setDisableBuffering(boolean disableBuffering) {
|
||||
this.disableBuffering = disableBuffering;
|
||||
}
|
||||
|
||||
public void setDisableDisconnectError(boolean disableDisconnectError) {
|
||||
this.disableDisconnectError = disableDisconnectError;
|
||||
}
|
||||
|
||||
public void setFullscreen(boolean fullscreen) {
|
||||
if (fullscreen == isFullscreen) {
|
||||
return; // Avoid generating events when nothing is changing
|
||||
|
@ -49,6 +49,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
private static final String PROP_PAUSED = "paused";
|
||||
private static final String PROP_MUTED = "muted";
|
||||
private static final String PROP_VOLUME = "volume";
|
||||
private static final String PROP_BACK_BUFFER_DURATION_MS = "backBufferDurationMs";
|
||||
private static final String PROP_BUFFER_CONFIG = "bufferConfig";
|
||||
private static final String PROP_BUFFER_CONFIG_MIN_BUFFER_MS = "minBufferMs";
|
||||
private static final String PROP_BUFFER_CONFIG_MAX_BUFFER_MS = "maxBufferMs";
|
||||
@ -64,6 +65,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
private static final String PROP_PLAY_IN_BACKGROUND = "playInBackground";
|
||||
private static final String PROP_DISABLE_FOCUS = "disableFocus";
|
||||
private static final String PROP_DISABLE_BUFFERING = "disableBuffering";
|
||||
private static final String PROP_DISABLE_DISCONNECT_ERROR = "disableDisconnectError";
|
||||
private static final String PROP_FULLSCREEN = "fullscreen";
|
||||
private static final String PROP_USE_TEXTURE_VIEW = "useTextureView";
|
||||
private static final String PROP_SELECTED_VIDEO_TRACK = "selectedVideoTrack";
|
||||
@ -294,11 +296,21 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
videoView.setDisableFocus(disableFocus);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_BACK_BUFFER_DURATION_MS, defaultInt = 0)
|
||||
public void setBackBufferDurationMs(final ReactExoplayerView videoView, final int backBufferDurationMs) {
|
||||
videoView.setBackBufferDurationMs(backBufferDurationMs);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_DISABLE_BUFFERING, defaultBoolean = false)
|
||||
public void setDisableBuffering(final ReactExoplayerView videoView, final boolean disableBuffering) {
|
||||
videoView.setDisableBuffering(disableBuffering);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_DISABLE_DISCONNECT_ERROR, defaultBoolean = false)
|
||||
public void setDisableDisconnectError(final ReactExoplayerView videoView, final boolean disableDisconnectError) {
|
||||
videoView.setDisableDisconnectError(disableDisconnectError);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_FULLSCREEN, defaultBoolean = false)
|
||||
public void setFullscreen(final ReactExoplayerView videoView, final boolean fullscreen) {
|
||||
videoView.setFullscreen(fullscreen);
|
||||
|
Loading…
Reference in New Issue
Block a user