diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b15ee6b05..ea5e43a69b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,39 @@ +## [6.6.2](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.6.1...v6.6.2) (2024-09-20) + + +### Features + +* **iOS:** rewrite DRM Module ([#4136](https://github.com/TheWidlarzGroup/react-native-video/issues/4136)) ([0e4c95d](https://github.com/TheWidlarzGroup/react-native-video/commit/0e4c95def968a4091fdd18d07215ba592eec99cb)) + +## [6.6.1](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.6.0...v6.6.1) (2024-09-18) + + +### Bug Fixes + +* **ios:** fix side loaded text track management ([#4180](https://github.com/TheWidlarzGroup/react-native-video/issues/4180)) ([7d43d5d](https://github.com/TheWidlarzGroup/react-native-video/commit/7d43d5d3da72495e94468756be21442f96cc7a89)) + +# [6.6.0](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.5.0...v6.6.0) (2024-09-18) + + +### Bug Fixes + +* **android:** ensure maxbitrate & selectedVideoTrack interact correctly ([#4155](https://github.com/TheWidlarzGroup/react-native-video/issues/4155)) ([7f6b500](https://github.com/TheWidlarzGroup/react-native-video/commit/7f6b500c82122325c326b6dcacaf7af8039b2b33)) +* **android:** ensure pause is well tken in account after onEnd ([#4147](https://github.com/TheWidlarzGroup/react-native-video/issues/4147)) ([b2fd8d6](https://github.com/TheWidlarzGroup/react-native-video/commit/b2fd8d62a10ee64e6208b43120ca9231008309c2)) +* **expo-plugin:** add check for existing service in AndroidManifest for notification controls ([#4172](https://github.com/TheWidlarzGroup/react-native-video/issues/4172)) ([0538b3b](https://github.com/TheWidlarzGroup/react-native-video/commit/0538b3b46801a535c76cf52db28cee76f2aeb0c5)) +* **ios:** ensure onBandwidthUpdate is reported only when value change ([#4149](https://github.com/TheWidlarzGroup/react-native-video/issues/4149)) ([809a730](https://github.com/TheWidlarzGroup/react-native-video/commit/809a73019836f95385891c2bba5c72b0610ffcb1)) +* **ios:** losing subtitle selection on foreground ([#3707](https://github.com/TheWidlarzGroup/react-native-video/issues/3707)) ([bee4123](https://github.com/TheWidlarzGroup/react-native-video/commit/bee4123402f4bc08dd2eb19ab0011ffdc795d0e3)) +* **JS:** improve loader api to allow function call instead of component ([#4171](https://github.com/TheWidlarzGroup/react-native-video/issues/4171)) ([835186a](https://github.com/TheWidlarzGroup/react-native-video/commit/835186a321e1940932a045a59e26e43a040fa334)) +* refactor side loaded text tracks management ([#4158](https://github.com/TheWidlarzGroup/react-native-video/issues/4158)) ([84a27f3](https://github.com/TheWidlarzGroup/react-native-video/commit/84a27f3d9f90624af3c5c3cbff50d754bab9baa4)) +* **sample:** remove warning on ios with NavigationBar ([#4148](https://github.com/TheWidlarzGroup/react-native-video/issues/4148)) ([e18769a](https://github.com/TheWidlarzGroup/react-native-video/commit/e18769ab3a6a7f4ebc459ab550f105f4d18f8201)) +* **visionOS:** remove unsupported apis ([#4154](https://github.com/TheWidlarzGroup/react-native-video/issues/4154)) ([2c1fc96](https://github.com/TheWidlarzGroup/react-native-video/commit/2c1fc964bf2cb97624c8cc37ff8138465619fc61)) + + +### Features + +* **android:** upgrade dependencies / media3 1.4.1 / androidxCore to 1.13.1 / androidxActivity 1.8.2 ([#4173](https://github.com/TheWidlarzGroup/react-native-video/issues/4173)) ([e57c7bd](https://github.com/TheWidlarzGroup/react-native-video/commit/e57c7bda5df7d624d90b20620859b8a4eb3f76b7)) + # [6.5.0](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.4.5...v6.5.0) (2024-09-04) diff --git a/android/build.gradle b/android/build.gradle index 5492c667f8..d153c93661 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -216,7 +216,7 @@ dependencies { //noinspection GradleDynamicVersion implementation "com.facebook.react:react-native:+" - implementation "androidx.core:core:$androidxCore_version" + implementation "androidx.core:core-ktx:$androidxCore_version" implementation "androidx.activity:activity-ktx:$androidxActivity_version" // For media playback using ExoPlayer diff --git a/android/gradle.properties b/android/gradle.properties index 46daceb29b..b474349ba7 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -4,12 +4,12 @@ RNVideo_targetSdkVersion=34 RNVideo_compileSdkVersion=34 RNVideo_ndkversion=26.1.10909125 RNVideo_buildToolsVersion=34.0.0 -RNVideo_media3Version=1.3.1 +RNVideo_media3Version=1.4.1 RNVideo_useExoplayerIMA=false RNVideo_useExoplayerRtsp=false RNVideo_useExoplayerSmoothStreaming=true RNVideo_useExoplayerDash=true RNVideo_useExoplayerHls=true -RNVideo_androidxCoreVersion=1.9.0 -RNVideo_androidxActivityVersion=1.7.0 +RNVideo_androidxCoreVersion=1.13.1 +RNVideo_androidxActivityVersion=1.8.2 RNVideo_buildFromMedia3Source=false diff --git a/android/src/main/java/com/brentvatne/common/api/SideLoadedTextTrackList.kt b/android/src/main/java/com/brentvatne/common/api/SideLoadedTextTrackList.kt index e3d519c408..494facdc0b 100644 --- a/android/src/main/java/com/brentvatne/common/api/SideLoadedTextTrackList.kt +++ b/android/src/main/java/com/brentvatne/common/api/SideLoadedTextTrackList.kt @@ -11,12 +11,18 @@ import com.facebook.react.bridge.ReadableMap class SideLoadedTextTrackList { var tracks = ArrayList() + /** return true if this and src are equals */ + override fun equals(other: Any?): Boolean { + if (other == null || other !is SideLoadedTextTrackList) return false + return tracks == other.tracks + } + companion object { fun parse(src: ReadableArray?): SideLoadedTextTrackList? { if (src == null) { return null } - var sideLoadedTextTrackList = SideLoadedTextTrackList() + val sideLoadedTextTrackList = SideLoadedTextTrackList() for (i in 0 until src.size()) { val textTrack: ReadableMap = src.getMap(i) sideLoadedTextTrackList.tracks.add(SideLoadedTextTrack.parse(textTrack)) diff --git a/android/src/main/java/com/brentvatne/common/api/Source.kt b/android/src/main/java/com/brentvatne/common/api/Source.kt index b9ea8bf762..1e0240224b 100644 --- a/android/src/main/java/com/brentvatne/common/api/Source.kt +++ b/android/src/main/java/com/brentvatne/common/api/Source.kt @@ -38,6 +38,9 @@ class Source { /** Will crop content end at specified position */ var cropEndMs: Int = -1 + /** Will virtually consider that content before contentStartTime is a preroll ad */ + var contentStartTime: Int = -1 + /** Allow to force stream content, necessary when uri doesn't contain content type (.mlp4, .m3u, ...) */ var extension: String? = null @@ -62,6 +65,11 @@ class Source { */ var cmcdProps: CMCDProps? = null + /** + * The list of sideLoaded text tracks + */ + var sideLoadedTextTracks: SideLoadedTextTrackList? = null + override fun hashCode(): Int = Objects.hash(uriString, uri, startPositionMs, cropStartMs, cropEndMs, extension, metadata, headers) /** return true if this and src are equals */ @@ -74,7 +82,9 @@ class Source { startPositionMs == other.startPositionMs && extension == other.extension && drmProps == other.drmProps && - cmcdProps == other.cmcdProps + contentStartTime == other.contentStartTime && + cmcdProps == other.cmcdProps && + sideLoadedTextTracks == other.sideLoadedTextTracks ) } @@ -133,12 +143,14 @@ class Source { private const val PROP_SRC_START_POSITION = "startPosition" private const val PROP_SRC_CROP_START = "cropStart" private const val PROP_SRC_CROP_END = "cropEnd" + private const val PROP_SRC_CONTENT_START_TIME = "contentStartTime" 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_DRM = "drm" private const val PROP_SRC_CMCD = "cmcd" private const val PROP_SRC_TEXT_TRACKS_ALLOW_CHUNKLESS_PREPARATION = "textTracksAllowChunklessPreparation" + private const val PROP_SRC_TEXT_TRACKS = "textTracks" @SuppressLint("DiscouragedApi") private fun getUriFromAssetId(context: Context, uriString: String): Uri? { @@ -194,10 +206,12 @@ class Source { source.startPositionMs = safeGetInt(src, PROP_SRC_START_POSITION, -1) source.cropStartMs = safeGetInt(src, PROP_SRC_CROP_START, -1) source.cropEndMs = safeGetInt(src, PROP_SRC_CROP_END, -1) + source.contentStartTime = safeGetInt(src, PROP_SRC_CONTENT_START_TIME, -1) source.extension = safeGetString(src, PROP_SRC_TYPE, null) source.drmProps = parse(safeGetMap(src, PROP_SRC_DRM)) source.cmcdProps = CMCDProps.parse(safeGetMap(src, PROP_SRC_CMCD)) source.textTracksAllowChunklessPreparation = safeGetBool(src, PROP_SRC_TEXT_TRACKS_ALLOW_CHUNKLESS_PREPARATION, true) + source.sideLoadedTextTracks = SideLoadedTextTrackList.parse(safeGetArray(src, PROP_SRC_TEXT_TRACKS)) val propSrcHeadersArray = safeGetArray(src, PROP_SRC_HEADERS) if (propSrcHeadersArray != null) { diff --git a/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.kt b/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.kt index 3ccdfb7425..026b19ab79 100644 --- a/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.kt +++ b/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.kt @@ -64,11 +64,11 @@ class VideoEventEmitter { audioTracks: ArrayList, textTracks: ArrayList, videoTracks: ArrayList, - trackId: String + trackId: String? ) -> Unit lateinit var onVideoError: (errorString: String, exception: Exception, errorCode: String) -> Unit lateinit var onVideoProgress: (currentPosition: Long, bufferedDuration: Long, seekableDuration: Long, currentPlaybackTime: Double) -> Unit - lateinit var onVideoBandwidthUpdate: (bitRateEstimate: Long, height: Int, width: Int, trackId: String) -> Unit + lateinit var onVideoBandwidthUpdate: (bitRateEstimate: Long, height: Int, width: Int, trackId: String?) -> Unit lateinit var onVideoPlaybackStateChanged: (isPlaying: Boolean, isSeeking: Boolean) -> Unit lateinit var onVideoSeek: (currentPosition: Long, seekTime: Long) -> Unit lateinit var onVideoEnd: () -> Unit @@ -108,7 +108,7 @@ class VideoEventEmitter { val naturalSize: WritableMap = aspectRatioToNaturalSize(videoWidth, videoHeight) putMap("naturalSize", naturalSize) - putString("trackId", trackId) + trackId?.let { putString("trackId", it) } putArray("videoTracks", videoTracksToArray(videoTracks)) putArray("audioTracks", audioTracksToArray(audioTracks)) putArray("textTracks", textTracksToArray(textTracks)) @@ -153,9 +153,13 @@ class VideoEventEmitter { onVideoBandwidthUpdate = { bitRateEstimate, height, width, trackId -> event.dispatch(EventTypes.EVENT_BANDWIDTH) { putDouble("bitrate", bitRateEstimate.toDouble()) - putInt("width", width) - putInt("height", height) - putString("trackId", trackId) + if (width > 0) { + putInt("width", width) + } + if (height > 0) { + putInt("height", height) + } + trackId?.let { putString("trackId", it) } } } onVideoPlaybackStateChanged = { isPlaying, isSeeking -> @@ -344,15 +348,19 @@ class VideoEventEmitter { private fun aspectRatioToNaturalSize(videoWidth: Int, videoHeight: Int): WritableMap = Arguments.createMap().apply { - putInt("width", videoWidth) - putInt("height", videoHeight) - val orientation = if (videoWidth > videoHeight) { - "landscape" - } else if (videoWidth < videoHeight) { - "portrait" - } else { - "square" + if (videoWidth > 0) { + putInt("width", videoWidth) + } + if (videoHeight > 0) { + putInt("height", videoHeight) } + + val orientation = when { + videoWidth > videoHeight -> "landscape" + videoWidth < videoHeight -> "portrait" + else -> "square" + } + putString("orientation", orientation) } } diff --git a/android/src/main/java/com/brentvatne/common/toolbox/ReactBridgeUtils.kt b/android/src/main/java/com/brentvatne/common/toolbox/ReactBridgeUtils.kt index 10f4752aee..b4cce42612 100644 --- a/android/src/main/java/com/brentvatne/common/toolbox/ReactBridgeUtils.kt +++ b/android/src/main/java/com/brentvatne/common/toolbox/ReactBridgeUtils.kt @@ -3,7 +3,6 @@ package com.brentvatne.common.toolbox import com.facebook.react.bridge.Dynamic import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap -import java.util.HashMap /* * Toolbox to safe parsing of