From f87a7938c6941c69915477fcf5f08c54a2635597 Mon Sep 17 00:00:00 2001 From: YangJH Date: Sat, 11 May 2024 03:38:34 +0900 Subject: [PATCH 1/6] fix(js): fix onPlaybackStateChanged callback (#3753) --- src/Video.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Video.tsx b/src/Video.tsx index f85524764a..7cdbc211cd 100644 --- a/src/Video.tsx +++ b/src/Video.tsx @@ -549,7 +549,7 @@ const Video = forwardRef( onVideoEnd={onEnd} onVideoBuffer={onBuffer ? onVideoBuffer : undefined} onVideoPlaybackStateChanged={ - onPlaybackRateChange ? onVideoPlaybackStateChanged : undefined + onPlaybackStateChanged ? onVideoPlaybackStateChanged : undefined } onVideoBandwidthUpdate={ onBandwidthUpdate ? _onBandwidthUpdate : undefined From 3f63fd076d5fc4ba120f7917f909e8f0419866b9 Mon Sep 17 00:00:00 2001 From: Olivier Bouillet <62574056+freeboub@users.noreply.github.com> Date: Sat, 11 May 2024 00:23:59 +0200 Subject: [PATCH 2/6] docs: bug template (#3760) * chore: fix bug template --- .github/ISSUE_TEMPLATE/bug-report.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 6fa8e0b3fa..11af4a629c 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -6,11 +6,9 @@ assignees: [] body: - type: markdown attributes: - value: Thanks for taking the time to fill out this bug report! - Please do not report issue on 5.2.1 version, this version is not maintained anymore. - Only issues on version > V6 will be handled. Please also ensure your issue is reproduced with the last release! + value: Thanks for taking the time to fill out this bug report! Please do not report issue on 5.2.1 version, this version is not maintained anymore. Only issues on version > V6 will be handled. Please also ensure your issue is reproduced with the last release! - - type: textarea + - type: input id: version attributes: label: Version From efb338ee2a87c11f8a0e83ec72c613e87b3e43cb Mon Sep 17 00:00:00 2001 From: Olivier Bouillet <62574056+freeboub@users.noreply.github.com> Date: Sat, 11 May 2024 18:57:59 +0200 Subject: [PATCH 3/6] chore(android): refactor side loaded text tracks (#3754) * perf: ensure we do not provide callback to native if no callback provided from app * chore: rework bufferConfig to make it more generic and reduce ReactExoplayerView code size * chore(android): refactor external text tracks management. Split parsing and tracks handling * chore: fix linter --- .../common/api/SideLoadedTextTrack.kt | 34 +++++++++++++++++++ .../common/api/SideLoadedTextTrackList.kt | 27 +++++++++++++++ .../exoplayer/ReactExoplayerView.java | 25 ++++++-------- .../exoplayer/ReactExoplayerViewManager.java | 4 ++- .../exoplayer/VideoPlaybackService.kt | 4 +-- 5 files changed, 75 insertions(+), 19 deletions(-) create mode 100644 android/src/main/java/com/brentvatne/common/api/SideLoadedTextTrack.kt create mode 100644 android/src/main/java/com/brentvatne/common/api/SideLoadedTextTrackList.kt diff --git a/android/src/main/java/com/brentvatne/common/api/SideLoadedTextTrack.kt b/android/src/main/java/com/brentvatne/common/api/SideLoadedTextTrack.kt new file mode 100644 index 0000000000..59408c78c4 --- /dev/null +++ b/android/src/main/java/com/brentvatne/common/api/SideLoadedTextTrack.kt @@ -0,0 +1,34 @@ +package com.brentvatne.common.api + +import android.net.Uri +import com.brentvatne.common.toolbox.ReactBridgeUtils +import com.facebook.react.bridge.ReadableMap + +/** + * Class representing a sideLoaded text track from application + * Do you use player import in this class + */ +class SideLoadedTextTrack { + var language: String? = null + var title: String? = null + var uri: Uri = Uri.EMPTY + var type: String? = null + companion object { + val SIDELOAD_TEXT_TRACK_LANGUAGE = "language" + val SIDELOAD_TEXT_TRACK_TITLE = "title" + val SIDELOAD_TEXT_TRACK_URI = "uri" + val SIDELOAD_TEXT_TRACK_TYPE = "type" + + fun parse(src: ReadableMap?): SideLoadedTextTrack { + val sideLoadedTextTrack = SideLoadedTextTrack() + if (src == null) { + return sideLoadedTextTrack + } + sideLoadedTextTrack.language = ReactBridgeUtils.safeGetString(src, SIDELOAD_TEXT_TRACK_LANGUAGE) + sideLoadedTextTrack.title = ReactBridgeUtils.safeGetString(src, SIDELOAD_TEXT_TRACK_TITLE, "") + sideLoadedTextTrack.uri = Uri.parse(ReactBridgeUtils.safeGetString(src, SIDELOAD_TEXT_TRACK_URI, "")) + sideLoadedTextTrack.type = ReactBridgeUtils.safeGetString(src, SIDELOAD_TEXT_TRACK_TYPE, "") + return sideLoadedTextTrack + } + } +} diff --git a/android/src/main/java/com/brentvatne/common/api/SideLoadedTextTrackList.kt b/android/src/main/java/com/brentvatne/common/api/SideLoadedTextTrackList.kt new file mode 100644 index 0000000000..e3d519c408 --- /dev/null +++ b/android/src/main/java/com/brentvatne/common/api/SideLoadedTextTrackList.kt @@ -0,0 +1,27 @@ +package com.brentvatne.common.api + +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.ReadableMap + +/** + * Class representing a list of sideLoaded text track from application + * Do you use player import in this class + */ + +class SideLoadedTextTrackList { + var tracks = ArrayList() + + companion object { + fun parse(src: ReadableArray?): SideLoadedTextTrackList? { + if (src == null) { + return null + } + var sideLoadedTextTrackList = SideLoadedTextTrackList() + for (i in 0 until src.size()) { + val textTrack: ReadableMap = src.getMap(i) + sideLoadedTextTrackList.tracks.add(SideLoadedTextTrack.parse(textTrack)) + } + return sideLoadedTextTrackList + } + } +} diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 5ddc2bd8d4..39108e9611 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -106,6 +106,8 @@ import com.brentvatne.common.api.BufferConfig; import com.brentvatne.common.api.ResizeMode; +import com.brentvatne.common.api.SideLoadedTextTrack; +import com.brentvatne.common.api.SideLoadedTextTrackList; import com.brentvatne.common.api.SubtitleStyle; import com.brentvatne.common.api.TimedMetadata; import com.brentvatne.common.api.Track; @@ -117,8 +119,6 @@ import com.brentvatne.receiver.AudioBecomingNoisyReceiver; import com.brentvatne.receiver.BecomingNoisyListener; import com.facebook.react.bridge.LifecycleEventListener; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.uimanager.ThemedReactContext; import com.google.ads.interactivemedia.v3.api.AdError; @@ -220,7 +220,7 @@ public class ReactExoplayerView extends FrameLayout implements private String videoTrackValue; private String textTrackType; private String textTrackValue; - private ReadableArray textTracks; + private SideLoadedTextTrackList textTracks; private boolean disableFocus; private boolean focusable = true; private boolean disableBuffering; @@ -995,17 +995,12 @@ private ArrayList buildTextSources() { return textSources; } - for (int i = 0; i < textTracks.size(); ++i) { - ReadableMap textTrack = textTracks.getMap(i); - String language = textTrack.getString("language"); - String title = textTrack.hasKey("title") - ? textTrack.getString("title") : language + " " + i; - Uri uri = Uri.parse(textTrack.getString("uri")); - MediaSource textSource = buildTextSource(title, uri, textTrack.getString("type"), - language); - if (textSource != null) { - textSources.add(textSource); - } + for (SideLoadedTextTrack track : textTracks.getTracks()) { + MediaSource textSource = buildTextSource(track.getTitle(), + track.getUri(), + track.getType(), + track.getLanguage()); + textSources.add(textSource); } return textSources; } @@ -1718,7 +1713,7 @@ public void setRawSrc(final Uri uri, final String extension) { } } - public void setTextTracks(ReadableArray textTracks) { + public void setTextTracks(SideLoadedTextTrackList textTracks) { this.textTracks = textTracks; reloadSource(); } diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java index 6b5b0d3070..c39b379772 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -14,6 +14,7 @@ import com.brentvatne.common.api.BufferConfig; import com.brentvatne.common.api.ResizeMode; +import com.brentvatne.common.api.SideLoadedTextTrackList; import com.brentvatne.common.api.SubtitleStyle; import com.brentvatne.common.react.VideoEventEmitter; import com.brentvatne.common.toolbox.DebugLog; @@ -309,7 +310,8 @@ public void setSelectedTextTrack(final ReactExoplayerView videoView, @ReactProp(name = PROP_TEXT_TRACKS) public void setPropTextTracks(final ReactExoplayerView videoView, @Nullable ReadableArray textTracks) { - videoView.setTextTracks(textTracks); + SideLoadedTextTrackList sideLoadedTextTracks = SideLoadedTextTrackList.Companion.parse(textTracks); + videoView.setTextTracks(sideLoadedTextTracks); } @ReactProp(name = PROP_PAUSED, defaultBoolean = false) diff --git a/android/src/main/java/com/brentvatne/exoplayer/VideoPlaybackService.kt b/android/src/main/java/com/brentvatne/exoplayer/VideoPlaybackService.kt index 80bf34ff3d..85cc878065 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/VideoPlaybackService.kt +++ b/android/src/main/java/com/brentvatne/exoplayer/VideoPlaybackService.kt @@ -72,9 +72,7 @@ class VideoPlaybackService : MediaSessionService() { // Callbacks - override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? { - return null - } + override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? = null override fun onBind(intent: Intent?): IBinder { super.onBind(intent) From 2d9484499cfb58d86b0aa82872d494a03fe67bba Mon Sep 17 00:00:00 2001 From: Olivier Bouillet <62574056+freeboub@users.noreply.github.com> Date: Sat, 11 May 2024 19:01:47 +0200 Subject: [PATCH 4/6] fix(ts): add missing type (#3757) * perf: ensure we do not provide callback to native if no callback provided from app * chore: rework bufferConfig to make it more generic and reduce ReactExoplayerView code size * fix(js): add missing type for cacheSizeMB --- src/specs/VideoNativeComponent.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/specs/VideoNativeComponent.ts b/src/specs/VideoNativeComponent.ts index fb299be26f..d5dc5079e5 100644 --- a/src/specs/VideoNativeComponent.ts +++ b/src/specs/VideoNativeComponent.ts @@ -102,6 +102,7 @@ type BufferConfig = Readonly<{ backBufferDurationMs?: Float; // Android minBackBufferMemoryReservePercent?: Float; minBufferMemoryReservePercent?: Float; + cacheSizeMB?: Float; }>; type SubtitleStyle = Readonly<{ From 1a48f190f020ed025a44f5b09ea9e044600be723 Mon Sep 17 00:00:00 2001 From: Olivier Bouillet <62574056+freeboub@users.noreply.github.com> Date: Sat, 11 May 2024 19:03:44 +0200 Subject: [PATCH 5/6] chore(android): clean up logs (#3758) * perf: ensure we do not provide callback to native if no callback provided from app * chore: rework bufferConfig to make it more generic and reduce ReactExoplayerView code size * chore(android): cleanup logs TAG --- .../brentvatne/exoplayer/ReactExoplayerView.java | 14 +++++++------- .../exoplayer/ReactExoplayerViewManager.java | 5 +++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 39108e9611..6dccaee0dc 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -588,13 +588,13 @@ private void initializePlayer() { DrmSessionManager drmSessionManager = initializePlayerDrm(self); if (drmSessionManager == null && self.drmUUID != null) { // Failed to intialize DRM session manager - cannot continue - DebugLog.e("ExoPlayer Exception", "Failed to initialize DRM Session Manager Framework!"); + DebugLog.e(TAG, "Failed to initialize DRM Session Manager Framework!"); eventEmitter.error("Failed to initialize DRM Session Manager Framework!", new Exception("DRM Session Manager Framework failure!"), "3003"); return; } if (activity == null) { - DebugLog.e("ExoPlayer Exception", "Failed to initialize Player!"); + DebugLog.e(TAG, "Failed to initialize Player!"); eventEmitter.error("Failed to initialize Player!", new Exception("Current Activity is null!"), "1001"); return; } @@ -606,8 +606,8 @@ private void initializePlayer() { initializePlayerSource(self, drmSessionManager); } catch (Exception ex) { self.playerNeedsSource = true; - DebugLog.e("ExoPlayer Exception", "Failed to initialize Player!"); - DebugLog.e("ExoPlayer Exception", ex.toString()); + DebugLog.e(TAG, "Failed to initialize Player!"); + DebugLog.e(TAG, ex.toString()); self.eventEmitter.error(ex.toString(), ex, "1001"); } }); @@ -617,8 +617,8 @@ private void initializePlayer() { } } catch (Exception ex) { self.playerNeedsSource = true; - DebugLog.e("ExoPlayer Exception", "Failed to initialize Player!"); - DebugLog.e("ExoPlayer Exception", ex.toString()); + DebugLog.e(TAG, "Failed to initialize Player!"); + DebugLog.e(TAG, ex.toString()); eventEmitter.error(ex.toString(), ex, "1001"); } }; @@ -734,7 +734,7 @@ private void initializePlayerSource(ReactExoplayerView self, DrmSessionManager d wait(); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); - DebugLog.e("ExoPlayer Exception", ex.toString()); + DebugLog.e(TAG, ex.toString()); } } diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java index c39b379772..24e9a004c8 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -35,6 +35,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager { + private static final String TAG = "ExoViewManager"; private static final String REACT_CLASS = "RCTVideo"; private static final String PROP_SRC = "src"; private static final String PROP_SRC_URI = "uri"; @@ -184,7 +185,7 @@ public void setSrc(final ReactExoplayerView videoView, @Nullable ReadableMap src try { imageUri = Uri.parse(imageUriString); } catch (Exception e) { - DebugLog.e("ExoPlayer Warning", "Could not parse imageUri in metadata"); + DebugLog.e(TAG, "Could not parse imageUri in metadata"); } customMetadata = new MediaMetadata.Builder() @@ -255,7 +256,7 @@ public void setResizeMode(final ReactExoplayerView videoView, final String resiz videoView.setResizeModeModifier(ResizeMode.RESIZE_MODE_FILL); break; default: - DebugLog.w("ExoPlayer Warning", "Unsupported resize mode: " + resizeMode + " - falling back to fit"); + DebugLog.w(TAG, "Unsupported resize mode: " + resizeMode + " - falling back to fit"); videoView.setResizeModeModifier(ResizeMode.RESIZE_MODE_FIT); break; } From e420418e8f74894c443bd232e99f9b860e1d0b93 Mon Sep 17 00:00:00 2001 From: Olivier Bouillet <62574056+freeboub@users.noreply.github.com> Date: Sat, 11 May 2024 22:02:04 +0200 Subject: [PATCH 6/6] feat(android): make buffering strategy dynamic (#3756) * chore: rework bufferConfig to make it more generic and reduce ReactExoplayerView code size * feat: expose bufferingStrategy to app and change default behavior rename disableBuffering undocumented prop to bufferingStrategy and document it. before this change, default was 'dependingOnMemory'. It can trigger some unnecessary gc() call on android. --- .../common/api/BufferingStrategy.kt | 47 ++++++++++++++++ .../exoplayer/ReactExoplayerView.java | 56 ++++++++++--------- .../exoplayer/ReactExoplayerViewManager.java | 11 ++-- docs/pages/component/props.mdx | 10 ++++ examples/basic/src/VideoPlayer.tsx | 2 + src/specs/VideoNativeComponent.ts | 3 + src/types/video.ts | 7 +++ 7 files changed, 105 insertions(+), 31 deletions(-) create mode 100644 android/src/main/java/com/brentvatne/common/api/BufferingStrategy.kt diff --git a/android/src/main/java/com/brentvatne/common/api/BufferingStrategy.kt b/android/src/main/java/com/brentvatne/common/api/BufferingStrategy.kt new file mode 100644 index 0000000000..9c48474cd0 --- /dev/null +++ b/android/src/main/java/com/brentvatne/common/api/BufferingStrategy.kt @@ -0,0 +1,47 @@ +package com.brentvatne.common.api + +import com.brentvatne.common.toolbox.DebugLog + +/** + * Define how exoplayer with load data and parsing helper + */ + +class BufferingStrategy { + + /** + * Define how exoplayer with load data + */ + enum class BufferingStrategyEnum { + /** + * default exoplayer strategy + */ + Default, + + /** + * never load more than needed + */ + DisableBuffering, + + /** + * use default strategy but pause loading when available memory is low + */ + DependingOnMemory + } + + companion object { + private const val TAG = "BufferingStrategy" + + /** + * companion function to transform input string to enum + */ + fun parse(src: String?): BufferingStrategyEnum { + if (src == null) return BufferingStrategyEnum.Default + return try { + BufferingStrategyEnum.valueOf(src) + } catch (e: Exception) { + DebugLog.e(TAG, "cannot parse buffering strategy " + src) + BufferingStrategyEnum.Default + } + } + } +} diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 6dccaee0dc..9eb60e2275 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -32,7 +32,6 @@ import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import androidx.core.view.WindowCompat; import androidx.core.view.WindowInsetsCompat; @@ -105,6 +104,7 @@ import androidx.media3.ui.LegacyPlayerControlView; import com.brentvatne.common.api.BufferConfig; +import com.brentvatne.common.api.BufferingStrategy; import com.brentvatne.common.api.ResizeMode; import com.brentvatne.common.api.SideLoadedTextTrack; import com.brentvatne.common.api.SideLoadedTextTrackList; @@ -223,7 +223,7 @@ public class ReactExoplayerView extends FrameLayout implements private SideLoadedTextTrackList textTracks; private boolean disableFocus; private boolean focusable = true; - private boolean disableBuffering; + private BufferingStrategy.BufferingStrategyEnum bufferingStrategy; private long contentStartTime = -1L; private boolean disableDisconnectError; private boolean preventsDisplaySleepDuringVideoPlayback = true; @@ -541,30 +541,34 @@ public RNVLoadControl(DefaultAllocator allocator, BufferConfig config) { @Override public boolean shouldContinueLoading(long playbackPositionUs, long bufferedDurationUs, float playbackSpeed) { - if (ReactExoplayerView.this.disableBuffering) { - return false; - } - int loadedBytes = getAllocator().getTotalBytesAllocated(); - boolean isHeapReached = availableHeapInBytes > 0 && loadedBytes >= availableHeapInBytes; - if (isHeapReached) { - return false; - } - long usedMemory = runtime.totalMemory() - runtime.freeMemory(); - long freeMemory = runtime.maxMemory() - usedMemory; - double minBufferMemoryReservePercent = bufferConfig.getMinBufferMemoryReservePercent() != BufferConfig.Companion.getBufferConfigPropUnsetDouble() - ? bufferConfig.getMinBufferMemoryReservePercent() - : ReactExoplayerView.DEFAULT_MIN_BUFFER_MEMORY_RESERVE; - long reserveMemory = (long)minBufferMemoryReservePercent * runtime.maxMemory(); - long bufferedMs = bufferedDurationUs / (long)1000; - if (reserveMemory > freeMemory && bufferedMs > 2000) { - // We don't have enough memory in reserve so we stop buffering to allow other components to use it instead - return false; - } - if (runtime.freeMemory() == 0) { - DebugLog.w("ExoPlayer Warning", "Free memory reached 0, forcing garbage collection"); - runtime.gc(); + if (bufferingStrategy == BufferingStrategy.BufferingStrategyEnum.DisableBuffering) { return false; + } else if (bufferingStrategy == BufferingStrategy.BufferingStrategyEnum.DependingOnMemory) { + // The goal of this algorithm is to pause video loading (increasing the buffer) + // when available memory on device become low. + int loadedBytes = getAllocator().getTotalBytesAllocated(); + boolean isHeapReached = availableHeapInBytes > 0 && loadedBytes >= availableHeapInBytes; + if (isHeapReached) { + return false; + } + long usedMemory = runtime.totalMemory() - runtime.freeMemory(); + long freeMemory = runtime.maxMemory() - usedMemory; + double minBufferMemoryReservePercent = bufferConfig.getMinBufferMemoryReservePercent() != BufferConfig.Companion.getBufferConfigPropUnsetDouble() + ? bufferConfig.getMinBufferMemoryReservePercent() + : ReactExoplayerView.DEFAULT_MIN_BUFFER_MEMORY_RESERVE; + long reserveMemory = (long) minBufferMemoryReservePercent * runtime.maxMemory(); + long bufferedMs = bufferedDurationUs / (long) 1000; + if (reserveMemory > freeMemory && bufferedMs > 2000) { + // We don't have enough memory in reserve so we stop buffering to allow other components to use it instead + return false; + } + if (runtime.freeMemory() == 0) { + DebugLog.w(TAG, "Free memory reached 0, forcing garbage collection"); + runtime.gc(); + return false; + } } + // "default" case or normal case for "DependingOnMemory" return super.shouldContinueLoading(playbackPositionUs, bufferedDurationUs, playbackSpeed); } } @@ -2077,8 +2081,8 @@ public void setShowNotificationControls(boolean showNotificationControls) { } } - public void setDisableBuffering(boolean disableBuffering) { - this.disableBuffering = disableBuffering; + public void setBufferingStrategy(BufferingStrategy.BufferingStrategyEnum _bufferingStrategy) { + bufferingStrategy = _bufferingStrategy; } public boolean getPreventsDisplaySleepDuringVideoPlayback() { diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java index 24e9a004c8..997a137e93 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -10,9 +10,9 @@ import androidx.media3.common.MediaMetadata; import androidx.media3.common.util.Util; import androidx.media3.datasource.RawResourceDataSource; -import androidx.media3.exoplayer.DefaultLoadControl; import com.brentvatne.common.api.BufferConfig; +import com.brentvatne.common.api.BufferingStrategy; import com.brentvatne.common.api.ResizeMode; import com.brentvatne.common.api.SideLoadedTextTrackList; import com.brentvatne.common.api.SubtitleStyle; @@ -73,7 +73,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager + +Configure buffering / data loading strategy. + + - **Default (default)**: use exoplayer default loading strategy + - **DisableBuffering**: never try to buffer more than needed. Be carefull using this value will stop playback. To be used with care. + - **DependingOnMemory**: use exoplayer default strategy, but stop buffering and starts gc if available memory is low | + ### `chapters` diff --git a/examples/basic/src/VideoPlayer.tsx b/examples/basic/src/VideoPlayer.tsx index d94baba5b6..663806f5d5 100644 --- a/examples/basic/src/VideoPlayer.tsx +++ b/examples/basic/src/VideoPlayer.tsx @@ -39,6 +39,7 @@ import Video, { OnSeekData, OnPlaybackStateChangedData, OnPlaybackRateChangeData, + BufferingStrategyType, } from 'react-native-video'; import ToggleControl from './ToggleControl'; import MultiValueControl, { @@ -934,6 +935,7 @@ class VideoPlayer extends Component { poster={this.state.poster} onPlaybackRateChange={this.onPlaybackRateChange} onPlaybackStateChanged={this.onPlaybackStateChanged} + bufferingStrategy={BufferingStrategyType.DEFAULT} /> ); diff --git a/src/specs/VideoNativeComponent.ts b/src/specs/VideoNativeComponent.ts index d5dc5079e5..1b383eaeb2 100644 --- a/src/specs/VideoNativeComponent.ts +++ b/src/specs/VideoNativeComponent.ts @@ -93,6 +93,8 @@ export type Seek = Readonly<{ tolerance?: Float; }>; +type BufferingStrategyType = WithDefault; + type BufferConfig = Readonly<{ minBufferMs?: Float; maxBufferMs?: Float; @@ -317,6 +319,7 @@ export interface VideoNativeProps extends ViewProps { subtitleStyle?: SubtitleStyle; // android useTextureView?: boolean; // Android useSecureView?: boolean; // Android + bufferingStrategy?: BufferingStrategyType; // Android onVideoLoad?: DirectEventHandler; onVideoLoadStart?: DirectEventHandler; onVideoAspectRatio?: DirectEventHandler; diff --git a/src/types/video.ts b/src/types/video.ts index f57e2b0ed3..e174bbbf75 100644 --- a/src/types/video.ts +++ b/src/types/video.ts @@ -68,6 +68,12 @@ export type Drm = Readonly<{ /* eslint-enable @typescript-eslint/no-unused-vars */ }>; +export enum BufferingStrategyType { + DEFAULT = 'Default', + DISABLE_BUFFERING = 'DisableBuffering', + DEPENDING_ON_MEMORY = 'DependingOnMemory', +} + export type BufferConfig = { minBufferMs?: number; maxBufferMs?: number; @@ -195,6 +201,7 @@ export interface ReactVideoProps extends ReactVideoEvents, ViewProps { audioOutput?: AudioOutput; // Mobile automaticallyWaitsToMinimizeStalling?: boolean; // iOS bufferConfig?: BufferConfig; // Android + bufferingStrategy?: BufferingStrategyType; chapters?: Chapters[]; // iOS contentStartTime?: number; // Android controls?: boolean;