Skip to content

Commit 8087310

Browse files
VEX-4579: Network loss handling (24i#5)
Add support for customizing back buffer duration and handle network errors gracefully to prevent releasing the player when network is lost.
1 parent f6cce0d commit 8087310

File tree

6 files changed

+87
-2
lines changed

6 files changed

+87
-2
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,10 +276,12 @@ var styles = StyleSheet.create({
276276
* [allowsExternalPlayback](#allowsexternalplayback)
277277
* [audioOnly](#audioonly)
278278
* [automaticallyWaitsToMinimizeStalling](#automaticallyWaitsToMinimizeStalling)
279+
* [backBufferDurationMs](#backBufferDurationMs)
279280
* [bufferConfig](#bufferconfig)
280281
* [controls](#controls)
281282
* [currentPlaybackTime](#currentPlaybackTime)
282283
* [disableFocus](#disableFocus)
284+
* [disableDisconnectError](#disableDisconnectError)
283285
* [filter](#filter)
284286
* [filterEnabled](#filterEnabled)
285287
* [fullscreen](#fullscreen)
@@ -367,6 +369,11 @@ A Boolean value that indicates whether the player should automatically delay pla
367369

368370
Platforms: iOS
369371

372+
#### backBufferDurationMs
373+
The number of milliseconds of buffer to keep before the current position. This allows rewinding without rebuffering within that duration.
374+
375+
Platforms: Android ExoPlayer
376+
370377
#### bufferConfig
371378
Adjust the buffer settings. This prop takes an object with one or more of the properties listed below.
372379

@@ -416,6 +423,13 @@ Determines whether video audio should override background music/audio in Android
416423

417424
Platforms: Android Exoplayer
418425

426+
#### disableDisconnectError
427+
Determines if the player needs to throw an error when connection is lost or not
428+
* **false (default)** - Player will throw an error when connection is lost
429+
* **true** - Player will keep trying to buffer when network connect is lost
430+
431+
Platforms: Android Exoplayer
432+
419433
### DRM
420434
To setup DRM please follow [this guide](./DRM.md)
421435

android-exoplayer/src/main/java/com/brentvatne/exoplayer/DefaultReactExoplayerConfig.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,28 @@
99
public class DefaultReactExoplayerConfig implements ReactExoplayerConfig {
1010

1111
private final DefaultBandwidthMeter bandwidthMeter;
12+
private boolean disableDisconnectError = false;
1213

1314
public DefaultReactExoplayerConfig(Context context) {
1415
this.bandwidthMeter = new DefaultBandwidthMeter.Builder(context).build();
1516
}
1617

17-
@Override
1818
public LoadErrorHandlingPolicy buildLoadErrorHandlingPolicy(int minLoadRetryCount) {
19+
if (this.disableDisconnectError) {
20+
// Use custom error handling policy to prevent throwing an error when losing network connection
21+
return new ReactExoplayerLoadErrorHandlingPolicy(minLoadRetryCount);
22+
}
1923
return new DefaultLoadErrorHandlingPolicy(minLoadRetryCount);
2024
}
2125

26+
public void setDisableDisconnectError(boolean disableDisconnectError) {
27+
this.disableDisconnectError = disableDisconnectError;
28+
}
29+
30+
public boolean getDisableDisconnectError() {
31+
return this.disableDisconnectError;
32+
}
33+
2234
@Override
2335
public DefaultBandwidthMeter getBandwidthMeter() {
2436
return bandwidthMeter;

android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerConfig.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,8 @@
99
public interface ReactExoplayerConfig {
1010
LoadErrorHandlingPolicy buildLoadErrorHandlingPolicy(int minLoadRetryCount);
1111

12+
void setDisableDisconnectError(boolean disableDisconnectError);
13+
boolean getDisableDisconnectError();
14+
1215
DefaultBandwidthMeter getBandwidthMeter();
1316
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.brentvatne.exoplayer;
2+
3+
import java.io.IOException;
4+
import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy;
5+
import com.google.android.exoplayer2.upstream.HttpDataSource.HttpDataSourceException;
6+
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy.LoadErrorInfo;
7+
import com.google.android.exoplayer2.C;
8+
9+
public final class ReactExoplayerLoadErrorHandlingPolicy extends DefaultLoadErrorHandlingPolicy {
10+
private int minLoadRetryCount = Integer.MAX_VALUE;
11+
12+
public ReactExoplayerLoadErrorHandlingPolicy(int minLoadRetryCount) {
13+
super(minLoadRetryCount);
14+
this.minLoadRetryCount = minLoadRetryCount;
15+
}
16+
17+
@Override
18+
public long getRetryDelayMsFor(LoadErrorInfo loadErrorInfo) {
19+
if (loadErrorInfo.exception instanceof HttpDataSourceException) {
20+
// Capture the error we get when there is no network connectivity and keep retrying it
21+
return 1000; // Retry every second
22+
} else if(loadErrorInfo.errorCount < this.minLoadRetryCount) {
23+
return Math.min((loadErrorInfo.errorCount - 1) * 1000, 5000); // Default timeout handling
24+
} else {
25+
return C.TIME_UNSET; // Done retrying and will return the error immediately
26+
}
27+
}
28+
29+
@Override
30+
public int getMinimumLoadableRetryCount(int dataType) {
31+
return Integer.MAX_VALUE;
32+
}
33+
}

android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class ReactExoplayerView extends FrameLayout implements
139139
private Handler mainHandler;
140140

141141
// Props from React
142+
private int backBufferDurationMs = DefaultLoadControl.DEFAULT_BACK_BUFFER_DURATION_MS;
142143
private Uri srcUri;
143144
private String extension;
144145
private boolean repeat;
@@ -151,6 +152,7 @@ class ReactExoplayerView extends FrameLayout implements
151152
private ReadableArray textTracks;
152153
private boolean disableFocus;
153154
private boolean disableBuffering;
155+
private boolean disableDisconnectError;
154156
private boolean preventsDisplaySleepDuringVideoPlayback = true;
155157
private float mProgressUpdateInterval = 250.0f;
156158
private boolean playInBackground = false;
@@ -434,7 +436,7 @@ public void run() {
434436
bufferForPlaybackAfterRebufferMs,
435437
-1,
436438
true,
437-
DefaultLoadControl.DEFAULT_BACK_BUFFER_DURATION_MS,
439+
backBufferDurationMs,
438440
DefaultLoadControl.DEFAULT_RETAIN_BACK_BUFFER_FROM_KEYFRAME
439441
);
440442
DefaultRenderersFactory renderersFactory =
@@ -527,6 +529,7 @@ private DrmSessionManager buildDrmSessionManager(UUID uuid,
527529
private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessionManager drmSessionManager) {
528530
int type = Util.inferContentType(!TextUtils.isEmpty(overrideExtension) ? "." + overrideExtension
529531
: uri.getLastPathSegment());
532+
config.setDisableDisconnectError(this.disableDisconnectError);
530533
switch (type) {
531534
case C.TYPE_SS:
532535
return new SsMediaSource.Factory(
@@ -1312,10 +1315,18 @@ public void setDisableFocus(boolean disableFocus) {
13121315
this.disableFocus = disableFocus;
13131316
}
13141317

1318+
public void setBackBufferDurationMs(int backBufferDurationMs) {
1319+
this.backBufferDurationMs = backBufferDurationMs;
1320+
}
1321+
13151322
public void setDisableBuffering(boolean disableBuffering) {
13161323
this.disableBuffering = disableBuffering;
13171324
}
13181325

1326+
public void setDisableDisconnectError(boolean disableDisconnectError) {
1327+
this.disableDisconnectError = disableDisconnectError;
1328+
}
1329+
13191330
public void setFullscreen(boolean fullscreen) {
13201331
if (fullscreen == isFullscreen) {
13211332
return; // Avoid generating events when nothing is changing

android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
4949
private static final String PROP_PAUSED = "paused";
5050
private static final String PROP_MUTED = "muted";
5151
private static final String PROP_VOLUME = "volume";
52+
private static final String PROP_BACK_BUFFER_DURATION_MS = "backBufferDurationMs";
5253
private static final String PROP_BUFFER_CONFIG = "bufferConfig";
5354
private static final String PROP_BUFFER_CONFIG_MIN_BUFFER_MS = "minBufferMs";
5455
private static final String PROP_BUFFER_CONFIG_MAX_BUFFER_MS = "maxBufferMs";
@@ -64,6 +65,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
6465
private static final String PROP_PLAY_IN_BACKGROUND = "playInBackground";
6566
private static final String PROP_DISABLE_FOCUS = "disableFocus";
6667
private static final String PROP_DISABLE_BUFFERING = "disableBuffering";
68+
private static final String PROP_DISABLE_DISCONNECT_ERROR = "disableDisconnectError";
6769
private static final String PROP_FULLSCREEN = "fullscreen";
6870
private static final String PROP_USE_TEXTURE_VIEW = "useTextureView";
6971
private static final String PROP_SELECTED_VIDEO_TRACK = "selectedVideoTrack";
@@ -294,11 +296,21 @@ public void setDisableFocus(final ReactExoplayerView videoView, final boolean di
294296
videoView.setDisableFocus(disableFocus);
295297
}
296298

299+
@ReactProp(name = PROP_BACK_BUFFER_DURATION_MS, defaultInt = 0)
300+
public void setBackBufferDurationMs(final ReactExoplayerView videoView, final int backBufferDurationMs) {
301+
videoView.setBackBufferDurationMs(backBufferDurationMs);
302+
}
303+
297304
@ReactProp(name = PROP_DISABLE_BUFFERING, defaultBoolean = false)
298305
public void setDisableBuffering(final ReactExoplayerView videoView, final boolean disableBuffering) {
299306
videoView.setDisableBuffering(disableBuffering);
300307
}
301308

309+
@ReactProp(name = PROP_DISABLE_DISCONNECT_ERROR, defaultBoolean = false)
310+
public void setDisableDisconnectError(final ReactExoplayerView videoView, final boolean disableDisconnectError) {
311+
videoView.setDisableDisconnectError(disableDisconnectError);
312+
}
313+
302314
@ReactProp(name = PROP_FULLSCREEN, defaultBoolean = false)
303315
public void setFullscreen(final ReactExoplayerView videoView, final boolean fullscreen) {
304316
videoView.setFullscreen(fullscreen);

0 commit comments

Comments
 (0)