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 into feat/moveViewTypeAndDrmInSource

# Conflicts:
#	android/src/main/java/com/brentvatne/common/api/Source.kt
#	android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java
#	android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java
#	docs/pages/component/props.mdx
#	examples/basic/ios/Podfile.lock
#	src/Video.tsx
#	src/specs/VideoNativeComponent.ts
#	src/types/video.ts
  • Loading branch information
freeboub committed Jun 27, 2024
2 parents 3d03f29 + b431d09 commit f352a59
Show file tree
Hide file tree
Showing 57 changed files with 4,645 additions and 607 deletions.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@


# [6.3.0](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.2.0...v6.3.0) (2024-06-22)


### Bug Fixes

* **android:** allow chunk less preparation ([#3913](https://github.com/TheWidlarzGroup/react-native-video/issues/3913)) ([264b57a](https://github.com/TheWidlarzGroup/react-native-video/commit/264b57aa2ed01b52c09b2992d5ca61e33871315b))
* **android:** avoid crash multiplayer with notification ([#3931](https://github.com/TheWidlarzGroup/react-native-video/issues/3931)) ([104ee70](https://github.com/TheWidlarzGroup/react-native-video/commit/104ee703bac0f7d5fb162d17c30f65f8071d07a6))
* **android:** show controls in notification on older androids ([#3886](https://github.com/TheWidlarzGroup/react-native-video/issues/3886)) ([098a754](https://github.com/TheWidlarzGroup/react-native-video/commit/098a754110a2c58fc18062769f4dd83775d20de4))
* **android:** use UI thread to pause when lost audio focus ([#3916](https://github.com/TheWidlarzGroup/react-native-video/issues/3916)) ([856b1dd](https://github.com/TheWidlarzGroup/react-native-video/commit/856b1dd58ba9bb1832397ee0fc86f778f737798f))
* **ios:** crash on ads after leaving the app ([#3911](https://github.com/TheWidlarzGroup/react-native-video/issues/3911)) ([3d6bc94](https://github.com/TheWidlarzGroup/react-native-video/commit/3d6bc9409c2111760620a821466b0ea0f1970681))
* **ios:** missing notification controls when enabled from start ([#3898](https://github.com/TheWidlarzGroup/react-native-video/issues/3898)) ([2d793db](https://github.com/TheWidlarzGroup/react-native-video/commit/2d793dbde16cc140d1e7b873c40ff4dec285e253))
* **JS:** safety check on resolve uri ([#3915](https://github.com/TheWidlarzGroup/react-native-video/issues/3915)) ([84bb910](https://github.com/TheWidlarzGroup/react-native-video/commit/84bb910d10e3e3d70f9e92b57c17de829d73218a))
* **typescript:** type checks on selectedTextTrack, selectedAudioTrack, selectedVideoTrack ([#3910](https://github.com/TheWidlarzGroup/react-native-video/issues/3910)) ([dc2a2ab](https://github.com/TheWidlarzGroup/react-native-video/commit/dc2a2ab863dc53fb2da1c2cea99e59e6d8387803))


### Features

* **android:** add `onControlsVisiblityChange` ([#3925](https://github.com/TheWidlarzGroup/react-native-video/issues/3925)) ([c2ce372](https://github.com/TheWidlarzGroup/react-native-video/commit/c2ce372bcf21e21b97878e7efe77780168d09a79))
* **ios:** add live key to now playing dict to decorate when livestream playing ([#3922](https://github.com/TheWidlarzGroup/react-native-video/issues/3922)) ([91751ab](https://github.com/TheWidlarzGroup/react-native-video/commit/91751abc870109e0a2667dfffbd2baa2e4cf997b))

# [6.2.0](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.1.2...v6.2.0) (2024-06-07)


Expand Down
85 changes: 65 additions & 20 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def ExoplayerDependenciesList = [
"useExoplayerHls",
"useExoplayerRtsp",
]
def media3_buildFromSource = safeExtGet('buildFromMedia3Source').toBoolean() ?: false

def ExoplayerDependencies = ExoplayerDependenciesList.collectEntries { property ->
[(property): safeExtGet(property)?.toBoolean() ?: false]
Expand All @@ -52,14 +53,17 @@ ExoplayerDependenciesList.each { propertyName ->
def propertyValue = ExoplayerDependencies[propertyName]
println "$propertyName: $propertyValue"
}
println "buildFromSource: $media3_buildFromSource"

// This string is used to define build path.
// As react native build output directory is react-native path of the module.
// We need to force a new path on each configuration change.
// If you add a new build parameter, please add the new value in this string
def configStringPath = ExoplayerDependencies.collect { property, value ->
property + value
}.join('').md5()
def configStringPath = ExoplayerDependencies
.collect { property, value -> property + value}
.join('')
.concat("buildFromSource:$media3_buildFromSource")
.md5()

if (isNewArchitectureEnabled()) {
apply plugin: "com.facebook.react"
Expand Down Expand Up @@ -191,46 +195,87 @@ dependencies {
implementation "androidx.activity:activity-ktx:$androidxActivity_version"

// For media playback using ExoPlayer
implementation "androidx.media3:media3-exoplayer:$media3_version"
if (media3_buildFromSource) {
implementation(project(":media-lib-exoplayer"))
} else {
implementation "androidx.media3:media3-exoplayer:$media3_version"
}

if (ExoplayerDependencies["useExoplayerSmoothStreaming"]) {
// For Smooth Streaming playback support with ExoPlayer
implementation "androidx.media3:media3-exoplayer-smoothstreaming:$media3_version"
if (media3_buildFromSource) {
implementation(project(":media-lib-exoplayer-smoothstreaming"))
} else {
implementation "androidx.media3:media3-exoplayer-smoothstreaming:$media3_version"
}
}

if (ExoplayerDependencies["useExoplayerDash"]) {
// For DASH playback support with ExoPlayer
implementation "androidx.media3:media3-exoplayer-dash:$media3_version"
if (media3_buildFromSource) {
implementation(project(":media-lib-exoplayer-dash"))
} else {
implementation "androidx.media3:media3-exoplayer-dash:$media3_version"
}
}

if (ExoplayerDependencies["useExoplayerHls"]) {
// For HLS playback support with ExoPlayer
implementation "androidx.media3:media3-exoplayer-hls:$media3_version"
// For HLS playback support with ExoPlayer
if (media3_buildFromSource) {
implementation(project(":media-lib-exoplayer-hls"))
} else {
implementation "androidx.media3:media3-exoplayer-hls:$media3_version"
}
}

// For RTSP playback support with ExoPlayer
if (ExoplayerDependencies["useExoplayerRtsp"]) {
implementation "androidx.media3:media3-exoplayer-rtsp:$media3_version"
if (media3_buildFromSource) {
implementation(project(":media-lib-exoplayer-rtsp"))
} else {
implementation "androidx.media3:media3-exoplayer-rtsp:$media3_version"
}
}

// For ad insertion using the Interactive Media Ads SDK with ExoPlayer
if (ExoplayerDependencies["useExoplayerIMA"]) {
implementation "androidx.media3:media3-exoplayer-ima:$media3_version"
if (media3_buildFromSource) {
implementation(project(":media-lib-exoplayer-ima"))
} else {
implementation "androidx.media3:media3-exoplayer-ima:$media3_version"
}
}

// For loading data using the OkHttp network stack
implementation "androidx.media3:media3-datasource-okhttp:$media3_version"
if (media3_buildFromSource) {
// For loading data using the OkHttp network stack
implementation(project(":media-lib-datasource-okhttp"))

// For building media playback UIs
implementation "androidx.media3:media3-ui:$media3_version"
// For building media playback UIs
implementation(project(":media-lib-ui"))

// For exposing and controlling media sessions
implementation "androidx.media3:media3-session:$media3_version"
// For exposing and controlling media sessions
implementation(project(":media-lib-session"))

// Common functionality for loading data
implementation "androidx.media3:media3-datasource:$media3_version"
// Common functionality used across multiple media libraries
implementation "androidx.media3:media3-common:$media3_version"
// Common functionality for loading data
implementation(project(":media-lib-datasource"))

// Common functionality used across multiple media libraries
implementation(project(":media-lib-common"))
} else {
// For loading data using the OkHttp network stack
implementation "androidx.media3:media3-datasource-okhttp:$media3_version"

// For building media playback UIs
implementation "androidx.media3:media3-ui:$media3_version"

// For exposing and controlling media sessions
implementation "androidx.media3:media3-session:$media3_version"

// Common functionality for loading data
implementation "androidx.media3:media3-datasource:$media3_version"

// Common functionality used across multiple media libraries
implementation "androidx.media3:media3-common:$media3_version"
}
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
1 change: 1 addition & 0 deletions android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ RNVideo_useExoplayerDash=true
RNVideo_useExoplayerHls=true
RNVideo_androidxCoreVersion=1.9.0
RNVideo_androidxActivityVersion=1.7.0
RNVideo_buildFromMedia3Source=false
17 changes: 4 additions & 13 deletions android/src/main/java/com/brentvatne/common/api/Source.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,10 @@ class Source {
*/
var drmProps: DRMProps? = null

/**
* Type of view to be used
*/
@ViewType.ViewType
var viewType = ViewType.VIEW_TYPE_SURFACE

/** enable chunckless preparation for HLS
/** enable chunkless preparation for HLS
* see:
*/
var textTracksAllowChuncklessPreparation: Boolean = false
var textTracksAllowChunklessPreparation: Boolean = false

override fun hashCode(): Int = Objects.hash(uriString, uri, startPositionMs, cropStartMs, cropEndMs, extension, metadata, headers)

Expand All @@ -74,7 +68,6 @@ class Source {
cropEndMs == other.cropEndMs &&
startPositionMs == other.startPositionMs &&
extension == other.extension &&
viewType == other.viewType &&
drmProps == other.drmProps
)
}
Expand Down Expand Up @@ -137,9 +130,8 @@ class Source {
private const val PROP_SRC_TYPE = "type"
private const val PROP_SRC_METADATA = "metadata"
private const val PROP_SRC_HEADERS = "requestHeaders"
private const val PROP_SRC_VIEW_TYPE = "viewType"
private const val PROP_SRC_DRM = "drm"
private const val PROP_SRC_TEXT_TRACKS_ALLOW_CHUNCKLESS_PREPARATION = "textTracksAllowChunklessPreparation"
private const val PROP_SRC_TEXT_TRACKS_ALLOW_CHUNKLESS_PREPARATION = "textTracksAllowChunklessPreparation"

@SuppressLint("DiscouragedApi")
private fun getUriFromAssetId(context: Context, uriString: String): Uri? {
Expand Down Expand Up @@ -196,9 +188,8 @@ class Source {
source.cropStartMs = safeGetInt(src, PROP_SRC_CROP_START, -1)
source.cropEndMs = safeGetInt(src, PROP_SRC_CROP_END, -1)
source.extension = safeGetString(src, PROP_SRC_TYPE, null)
source.viewType = safeGetInt(src, PROP_SRC_VIEW_TYPE, ViewType.VIEW_TYPE_SURFACE)
source.drmProps = parse(safeGetMap(src, PROP_SRC_DRM))
source.textTracksAllowChuncklessPreparation = safeGetBool(src, PROP_SRC_TEXT_TRACKS_ALLOW_CHUNCKLESS_PREPARATION, true)
source.textTracksAllowChunklessPreparation = safeGetBool(src, PROP_SRC_TEXT_TRACKS_ALLOW_CHUNKLESS_PREPARATION, true)

val propSrcHeadersArray = safeGetArray(src, PROP_SRC_HEADERS)
if (propSrcHeadersArray != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public VideoEventEmitter(ReactContext reactContext) {
private static final String EVENT_ERROR = "onVideoError";
private static final String EVENT_PROGRESS = "onVideoProgress";
private static final String EVENT_BANDWIDTH = "onVideoBandwidthUpdate";
private static final String EVENT_CONTROLS_VISIBILITY_CHANGE = "onControlsVisibilityChange";
private static final String EVENT_SEEK = "onVideoSeek";
private static final String EVENT_END = "onVideoEnd";
private static final String EVENT_FULLSCREEN_WILL_PRESENT = "onVideoFullscreenPlayerWillPresent";
Expand Down Expand Up @@ -89,6 +90,7 @@ public VideoEventEmitter(ReactContext reactContext) {
EVENT_TEXT_TRACK_DATA_CHANGED,
EVENT_VIDEO_TRACKS,
EVENT_BANDWIDTH,
EVENT_CONTROLS_VISIBILITY_CHANGE,
EVENT_ON_RECEIVE_AD_EVENT
};

Expand Down Expand Up @@ -120,6 +122,7 @@ public VideoEventEmitter(ReactContext reactContext) {
EVENT_TEXT_TRACK_DATA_CHANGED,
EVENT_VIDEO_TRACKS,
EVENT_BANDWIDTH,
EVENT_CONTROLS_VISIBILITY_CHANGE,
EVENT_ON_RECEIVE_AD_EVENT
})
@interface VideoEvents {
Expand Down Expand Up @@ -164,6 +167,8 @@ public VideoEventEmitter(ReactContext reactContext) {

private static final String EVENT_PROP_IS_PLAYING = "isPlaying";

private static final String EVENT_CONTROLS_VISIBLE = "isVisible";

public void setViewId(int viewId) {
this.viewId = viewId;
}
Expand Down Expand Up @@ -354,6 +359,12 @@ public void end() {
receiveEvent(EVENT_END, null);
}

public void controlsVisibilityChanged(boolean isVisible) {
WritableMap map = Arguments.createMap();
map.putBoolean(EVENT_CONTROLS_VISIBLE, isVisible);
receiveEvent(EVENT_CONTROLS_VISIBILITY_CHANGE, map);
}

public void fullscreenWillPresent() {
receiveEvent(EVENT_FULLSCREEN_WILL_PRESENT, null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@

@SuppressLint("ViewConstructor")
public final class ExoPlayerView extends FrameLayout implements AdViewProvider {

private final static String TAG = "ExoPlayerView";
private View surfaceView;
private final View shutterView;
Expand All @@ -46,6 +45,7 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
private final ViewGroup.LayoutParams layoutParams;
private final FrameLayout adOverlayFrameLayout;

private @ViewType.ViewType int viewType = ViewType.VIEW_TYPE_SURFACE;
private boolean hideShutterView = false;

public ExoPlayerView(Context context) {
Expand Down Expand Up @@ -75,7 +75,7 @@ public ExoPlayerView(Context context) {
subtitleLayout.setUserDefaultStyle();
subtitleLayout.setUserDefaultTextSize();

updateSurfaceView(ViewType.VIEW_TYPE_SURFACE);
updateSurfaceView(viewType);

adOverlayFrameLayout = new FrameLayout(context);

Expand Down Expand Up @@ -129,6 +129,7 @@ public void setShutterColor(Integer color) {
}

public void updateSurfaceView(@ViewType.ViewType int viewType) {
this.viewType = viewType;
boolean viewNeedRefresh = false;
if (viewType == ViewType.VIEW_TYPE_SURFACE || viewType == ViewType.VIEW_TYPE_SURFACE_SECURE) {
if (!(surfaceView instanceof SurfaceView)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
import com.brentvatne.common.toolbox.DebugLog;
import com.brentvatne.react.BuildConfig;
import com.brentvatne.react.R;
import com.brentvatne.react.ReactNativeVideoManager;
import com.brentvatne.receiver.AudioBecomingNoisyReceiver;
import com.brentvatne.receiver.BecomingNoisyListener;
import com.facebook.react.bridge.LifecycleEventListener;
Expand Down Expand Up @@ -257,6 +258,9 @@ public class ReactExoplayerView extends FrameLayout implements
private long lastDuration = -1;

private boolean viewHasDropped = false;

private String instanceId = String.valueOf(UUID.randomUUID());

private void updateProgress() {
if (player != null) {
if (playerControlView != null && isPlayingAd() && controls) {
Expand Down Expand Up @@ -412,6 +416,12 @@ private void togglePlayerControlVisibility() {
private void initializePlayerControl() {
if (playerControlView == null) {
playerControlView = new LegacyPlayerControlView(getContext());
playerControlView.addVisibilityListener(new LegacyPlayerControlView.VisibilityListener() {
@Override
public void onVisibilityChange(int visibility) {
eventEmitter.controlsVisibilityChanged(visibility == View.VISIBLE);
}
});
}

if (fullScreenPlayerView == null) {
Expand Down Expand Up @@ -575,6 +585,10 @@ private void refreshDebugState() {
}
}

public void setViewType(int viewType) {
exoPlayerView.updateSurfaceView(viewType);
}

private class RNVLoadControl extends DefaultLoadControl {
private final int availableHeapInBytes;
private final Runtime runtime;
Expand Down Expand Up @@ -650,7 +664,6 @@ private void initializePlayer() {
}
try {
if (player == null) {
exoPlayerView.updateSurfaceView(source.getViewType());
// Initialize core configuration and listeners
initializePlayerCore(self);
}
Expand Down Expand Up @@ -747,6 +760,7 @@ private void initializePlayerCore(ReactExoplayerView self) {
.setLoadControl(loadControl)
.setMediaSourceFactory(mediaSourceFactory)
.build();
ReactNativeVideoManager.Companion.getInstance().onInstanceCreated(instanceId, player);
refreshDebugState();
player.addListener(self);
player.setVolume(muted ? 0.f : audioVolume * 1);
Expand Down Expand Up @@ -1048,7 +1062,7 @@ private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessi

mediaSourceFactory = new HlsMediaSource.Factory(
mediaDataSourceFactory
).setAllowChunklessPreparation(source.getTextTracksAllowChuncklessPreparation());
).setAllowChunklessPreparation(source.getTextTracksAllowChunklessPreparation());
break;
case CONTENT_TYPE_OTHER:
if ("asset".equals(uri.getScheme())) {
Expand Down Expand Up @@ -1146,6 +1160,7 @@ private void releasePlayer() {
player.removeListener(this);
trackSelector = null;

ReactNativeVideoManager.Companion.getInstance().onInstanceRemoved(instanceId, player);
player = null;
}

Expand Down Expand Up @@ -1174,12 +1189,16 @@ private OnAudioFocusChangedListener(ReactExoplayerView view, ThemedReactContext

@Override
public void onAudioFocusChange(int focusChange) {
Activity activity = themedReactContext.getCurrentActivity();

switch (focusChange) {
case AudioManager.AUDIOFOCUS_LOSS:
view.hasAudioFocus = false;
view.eventEmitter.audioFocusChanged(false);
// FIXME this pause can cause issue if content doesn't have pause capability (can happen on live channel)
view.pausePlayback();
if (activity != null) {
activity.runOnUiThread(view::pausePlayback);
}
view.audioManager.abandonAudioFocus(this);
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
Expand All @@ -1193,7 +1212,6 @@ public void onAudioFocusChange(int focusChange) {
break;
}

Activity activity = themedReactContext.getCurrentActivity();
if (view.player != null && activity != null) {
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
// Lower the volume
Expand Down
Loading

0 comments on commit f352a59

Please sign in to comment.