From 486ea63a8a9c356b36de04a37ba9d54e5aefef0e Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sun, 4 Jan 2026 14:33:16 +0530 Subject: [PATCH 1/4] fixing exo crash and some UI flaws --- .../player/controls/PlayerControls.tsx | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/components/player/controls/PlayerControls.tsx b/src/components/player/controls/PlayerControls.tsx index 444666c..2a78f05 100644 --- a/src/components/player/controls/PlayerControls.tsx +++ b/src/components/player/controls/PlayerControls.tsx @@ -115,6 +115,13 @@ export const PlayerControls: React.FC = ({ /* Animations - State & Refs */ const [showBackwardSign, setShowBackwardSign] = React.useState(false); const [showForwardSign, setShowForwardSign] = React.useState(false); + const [previewTime, setPreviewTime] = React.useState(currentTime); + const isSlidingRef = React.useRef(false); + React.useEffect(() => { + if (!isSlidingRef.current) { + setPreviewTime(currentTime); + } + }, [currentTime]); /* Separate Animations for Each Button */ const backwardPressAnim = React.useRef(new Animated.Value(0)).current; @@ -280,10 +287,22 @@ export const PlayerControls: React.FC = ({ }} minimumValue={0} maximumValue={duration || 1} - value={currentTime} - onValueChange={onSliderValueChange} - onSlidingStart={onSlidingStart} - onSlidingComplete={onSlidingComplete} + + value={previewTime} + + onValueChange={(v) => setPreviewTime(v)} + + onSlidingStart={() => { + isSlidingRef.current = true; + onSlidingStart(); + }} + + onSlidingComplete={(v) => { + isSlidingRef.current = false; + setPreviewTime(v); + onSlidingComplete(v); + }} + minimumTrackTintColor={currentTheme.colors.primary} maximumTrackTintColor={currentTheme.colors.mediumEmphasis} thumbTintColor={Platform.OS === 'android' ? currentTheme.colors.white : undefined} @@ -608,4 +627,4 @@ export const PlayerControls: React.FC = ({ ); }; -export default PlayerControls; \ No newline at end of file +export default PlayerControls; From 5bd9f4110443122808ed134da43c97c092c61b32 Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sun, 4 Jan 2026 14:36:50 +0530 Subject: [PATCH 2/4] decreasing player refresh time from 4 times per second to 2 times , to prevent crashes with heavy files --- .../main/java/com/brentvatne/exoplayer/ReactExoplayerView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 44d8be2..049ef69 100644 --- a/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -244,7 +244,7 @@ public class ReactExoplayerView extends FrameLayout implements private BufferingStrategy.BufferingStrategyEnum bufferingStrategy; private boolean disableDisconnectError; private boolean preventsDisplaySleepDuringVideoPlayback = true; - private float mProgressUpdateInterval = 250.0f; + private float mProgressUpdateInterval = 500.0f; protected boolean playInBackground = false; private boolean mReportBandwidth = false; private boolean controls = false; From 4fdda9a1848cddc6f4552493cdba6b208990034b Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sun, 4 Jan 2026 15:25:27 +0530 Subject: [PATCH 3/4] several exoplayer optimizations to prevent crashes with huge file sizes --- .../exoplayer/ReactExoplayerView.java | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 049ef69..cb6f869 100644 --- a/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -161,7 +161,7 @@ public class ReactExoplayerView extends FrameLayout implements AdEvent.AdEventListener, AdErrorEvent.AdErrorListener { - public static final double DEFAULT_MAX_HEAP_ALLOCATION_PERCENT = 1; + public static final double DEFAULT_MAX_HEAP_ALLOCATION_PERCENT = 0.5; public static final double DEFAULT_MIN_BUFFER_MEMORY_RESERVE = 0; private static final String TAG = "ReactExoplayerView"; @@ -244,7 +244,7 @@ public class ReactExoplayerView extends FrameLayout implements private BufferingStrategy.BufferingStrategyEnum bufferingStrategy; private boolean disableDisconnectError; private boolean preventsDisplaySleepDuringVideoPlayback = true; - private float mProgressUpdateInterval = 500.0f; + private float mProgressUpdateInterval = 1000.0f; protected boolean playInBackground = false; private boolean mReportBandwidth = false; private boolean controls = false; @@ -642,6 +642,8 @@ public class ReactExoplayerView extends FrameLayout implements } private void initializePlayer() { + drmRetryCount = 0; + hasDrmFailed = false; disableCache = ReactNativeVideoManager.Companion.getInstance().shouldDisableCache(source); ReactExoplayerView self = this; @@ -664,10 +666,14 @@ public class ReactExoplayerView extends FrameLayout implements PictureInPictureUtil.applyAutoEnterEnabled(themedReactContext, pictureInPictureParamsBuilder, this.enterPictureInPictureOnLeave); } - if (!source.isLocalAssetFile() && !source.isAsset() && source.getBufferConfig().getCacheSize() > 0) { + long requestedCacheSize = source.getBufferConfig().getCacheSize(); + long MAX_SAFE_CACHE_SIZE = 100L * 1024 * 1024; + long effectiveCacheSize = Math.min(requestedCacheSize, MAX_SAFE_CACHE_SIZE); + if (!source.isLocalAssetFile() && !source.isAsset() && effectiveCacheSize > 0) { RNVSimpleCache.INSTANCE.setSimpleCache( this.getContext(), - source.getBufferConfig().getCacheSize()); + effectiveCacheSize + ); useCache = true; } else { useCache = false; @@ -876,13 +882,10 @@ public class ReactExoplayerView extends FrameLayout implements MediaSource mediaSource = Objects.requireNonNullElse(mediaSourceWithAds, videoSource); // wait for player to be set - while (player == null) { - try { - wait(); - } catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - DebugLog.e(TAG, ex.toString()); - } + if (player == null) { + DebugLog.w(TAG, "Player not ready yet, aborting source initialization"); + playerNeedsSource = true; + return; } boolean haveResumePosition = resumeWindow != C.INDEX_UNSET; @@ -1993,13 +1996,15 @@ public class ReactExoplayerView extends FrameLayout implements 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(); - setPlayWhenReady(true); - return; - } + if (drmRetryCount < 1) { + drmRetryCount++; + hasDrmFailed = true; + playerNeedsSource = true; + updateResumePosition(); + initializePlayer(); + setPlayWhenReady(true); + return; + } break; default: break; From 59f77ac83117c33f968bda078a78c6f41f8c39ec Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sun, 4 Jan 2026 16:17:16 +0530 Subject: [PATCH 4/4] optimisations for exo --- .../com/brentvatne/exoplayer/ReactExoplayerView.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index cb6f869..a939148 100644 --- a/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -270,6 +270,7 @@ public class ReactExoplayerView extends FrameLayout implements private final String instanceId = String.valueOf(UUID.randomUUID()); private CmcdConfiguration.Factory cmcdConfigurationFactory; + private static final ExecutorService SHARED_EXECUTOR = Executors.newSingleThreadExecutor(); public void setCmcdConfigurationFactory(CmcdConfiguration.Factory factory) { this.cmcdConfigurationFactory = factory; @@ -683,8 +684,7 @@ public class ReactExoplayerView extends FrameLayout implements exoPlayerView.invalidateAspectRatio(); // DRM session manager creation must be done on a different thread to prevent // crashes so we start a new thread - ExecutorService es = Executors.newSingleThreadExecutor(); - es.execute(() -> { + SHARED_EXECUTOR.execute(() -> { // DRM initialization must run on a different thread if (viewHasDropped && runningSource == source) { return; @@ -1518,8 +1518,7 @@ public class ReactExoplayerView extends FrameLayout implements ArrayList textTracks = getTextTrackInfo(); if (source.getContentStartTime() != -1) { - ExecutorService es = Executors.newSingleThreadExecutor(); - es.execute(() -> { + SHARED_EXECUTOR.execute(() -> { // To prevent ANRs caused by getVideoTrackInfo we run this on a different thread // and notify the player only when we're done ArrayList videoTracks = getVideoTrackInfoFromManifest(); @@ -1632,12 +1631,11 @@ public class ReactExoplayerView extends FrameLayout implements // conditions @WorkerThread private ArrayList getVideoTrackInfoFromManifest(int retryCount) { - ExecutorService es = Executors.newSingleThreadExecutor(); final DataSource dataSource = this.mediaDataSourceFactory.createDataSource(); final Uri sourceUri = source.getUri(); final long startTime = source.getContentStartTime() * 1000 - 100; // s -> ms with 100ms offset - Future> result = es.submit(new Callable() { + Future> result = SHARED_EXECUTOR.submit(new Callable>() { final DataSource ds = dataSource; final Uri uri = sourceUri; final long startTimeUs = startTime * 1000; // ms -> us @@ -1687,7 +1685,6 @@ public class ReactExoplayerView extends FrameLayout implements if (results == null && retryCount < 1) { return this.getVideoTrackInfoFromManifest(++retryCount); } - es.shutdown(); return results; } catch (Exception e) { DebugLog.w(TAG, "error in getVideoTrackInfoFromManifest handling request:" + e.getMessage());