Skip to content

Commit

Permalink
Merge branch 'master' of github.com:react-native-video/react-native-v…
Browse files Browse the repository at this point in the history
…ideo
  • Loading branch information
freeboub committed May 11, 2024
2 parents 17f2385 + e420418 commit 485f867
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 64 deletions.
6 changes: 2 additions & 4 deletions .github/ISSUE_TEMPLATE/bug-report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
}
}
}
Original file line number Diff line number Diff line change
@@ -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
}
}
}
Original file line number Diff line number Diff line change
@@ -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<SideLoadedTextTrack>()

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
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -105,7 +104,10 @@
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;
import com.brentvatne.common.api.SubtitleStyle;
import com.brentvatne.common.api.TimedMetadata;
import com.brentvatne.common.api.Track;
Expand All @@ -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;
Expand Down Expand Up @@ -220,10 +220,10 @@ 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;
private BufferingStrategy.BufferingStrategyEnum bufferingStrategy;
private long contentStartTime = -1L;
private boolean disableDisconnectError;
private boolean preventsDisplaySleepDuringVideoPlayback = true;
Expand Down Expand Up @@ -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);
}
}
Expand All @@ -588,13 +592,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;
}
Expand All @@ -606,8 +610,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");
}
});
Expand All @@ -617,8 +621,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");
}
};
Expand Down Expand Up @@ -734,7 +738,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());
}
}

Expand Down Expand Up @@ -995,17 +999,12 @@ private ArrayList<MediaSource> 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;
}
Expand Down Expand Up @@ -1718,7 +1717,7 @@ public void setRawSrc(final Uri uri, final String extension) {
}
}

public void setTextTracks(ReadableArray textTracks) {
public void setTextTracks(SideLoadedTextTrackList textTracks) {
this.textTracks = textTracks;
reloadSource();
}
Expand Down Expand Up @@ -2082,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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
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;
import com.brentvatne.common.react.VideoEventEmitter;
import com.brentvatne.common.toolbox.DebugLog;
Expand All @@ -34,6 +35,7 @@

public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerView> {

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";
Expand Down Expand Up @@ -71,7 +73,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
private static final String PROP_PLAY_IN_BACKGROUND = "playInBackground";
private static final String PROP_CONTENT_START_TIME = "contentStartTime";
private static final String PROP_DISABLE_FOCUS = "disableFocus";
private static final String PROP_DISABLE_BUFFERING = "disableBuffering";
private static final String PROP_BUFFERING_STRATEGY = "bufferingStrategy";
private static final String PROP_DISABLE_DISCONNECT_ERROR = "disableDisconnectError";
private static final String PROP_FOCUSABLE = "focusable";
private static final String PROP_FULLSCREEN = "fullscreen";
Expand Down Expand Up @@ -183,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()
Expand Down Expand Up @@ -254,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;
}
Expand Down Expand Up @@ -309,7 +311,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)
Expand Down Expand Up @@ -377,9 +380,10 @@ public void setContentStartTime(final ReactExoplayerView videoView, final int co
videoView.setContentStartTime(contentStartTime);
}

@ReactProp(name = PROP_DISABLE_BUFFERING, defaultBoolean = false)
public void setDisableBuffering(final ReactExoplayerView videoView, final boolean disableBuffering) {
videoView.setDisableBuffering(disableBuffering);
@ReactProp(name = PROP_BUFFERING_STRATEGY)
public void setBufferingStrategy(final ReactExoplayerView videoView, final String bufferingStrategy) {
BufferingStrategy.BufferingStrategyEnum strategy = BufferingStrategy.Companion.parse(bufferingStrategy);
videoView.setBufferingStrategy(strategy);
}

@ReactProp(name = PROP_DISABLE_DISCONNECT_ERROR, defaultBoolean = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 485f867

Please sign in to comment.