diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 7d16832da..ba428917c 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -14,7 +14,7 @@ lint: - actionlint@1.6.27 - prettier@3.2.5 - swiftlint@0.54.0 - - checkov@3.2.60 + - checkov@3.2.71 - trivy@0.50.1 - trufflehog@3.71.0 - oxipng@9.0.0 @@ -26,7 +26,7 @@ lint: - shellcheck@0.10.0 - git-diff-check - markdownlint@0.39.0 - - buildifier@7.1.0 + - buildifier@7.1.1 runtimes: enabled: - python@3.10.8 diff --git a/packages/react-native-hms/android/src/main/java/com/reactnativehmssdk/HMSDecoder.kt b/packages/react-native-hms/android/src/main/java/com/reactnativehmssdk/HMSDecoder.kt index 9aa120573..9f8cc8b5b 100644 --- a/packages/react-native-hms/android/src/main/java/com/reactnativehmssdk/HMSDecoder.kt +++ b/packages/react-native-hms/android/src/main/java/com/reactnativehmssdk/HMSDecoder.kt @@ -747,6 +747,9 @@ object HMSDecoder { variant.startedAt?.let { input.putString("startedAt", it.toString()) } + variant.playlistType?.let { + input.putString("playlistType", it.name.uppercase()) + } variants.pushMap(input) } } diff --git a/packages/react-native-hms/android/src/main/java/com/reactnativehmssdk/HMSHLSPlayer.kt b/packages/react-native-hms/android/src/main/java/com/reactnativehmssdk/HMSHLSPlayer.kt index 1389eb20b..123f7441b 100644 --- a/packages/react-native-hms/android/src/main/java/com/reactnativehmssdk/HMSHLSPlayer.kt +++ b/packages/react-native-hms/android/src/main/java/com/reactnativehmssdk/HMSHLSPlayer.kt @@ -3,12 +3,16 @@ package com.reactnativehmssdk import android.annotation.SuppressLint import android.content.Context import android.view.LayoutInflater +import android.view.View import android.widget.FrameLayout import androidx.media3.common.Player import androidx.media3.common.VideoSize +import androidx.media3.common.text.CueGroup import androidx.media3.ui.PlayerView import com.facebook.react.bridge.Arguments import com.facebook.react.bridge.ReactContext +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.ReadableMap import com.facebook.react.bridge.WritableMap import com.facebook.react.uimanager.events.RCTEventEmitter import live.hms.hls_player.* @@ -25,6 +29,7 @@ class HMSHLSPlayer(context: ReactContext) : FrameLayout(context) { private var hmsHlsPlayer: HmsHlsPlayer? = null // 100ms HLS Player private var hmssdkInstance: HMSSDK? = null private var statsMonitorAttached = false + private var shouldSendCaptionsToJS = false private val hmsHlsPlaybackEventsObject = object : HmsHlsPlaybackEvents { override fun onCue(cue: HmsHlsCue) { @@ -115,6 +120,7 @@ class HMSHLSPlayer(context: ReactContext) : FrameLayout(context) { val localPlayerView = view.findViewById(R.id.hls_view) playerView = localPlayerView localPlayerView.useController = false + localPlayerView.subtitleView?.visibility = View.GONE val hmssdkCollection = context.getNativeModule(HMSManager::class.java)?.getHmsInstance() hmssdkInstance = hmssdkCollection?.get("12345")?.hmsSDK @@ -144,6 +150,13 @@ class HMSHLSPlayer(context: ReactContext) : FrameLayout(context) { sendHLSPlaybackEventToJS(HMSHLSPlayerConstants.ON_PLAYBACK_RESOLUTION_CHANGE_EVENT, data) } } + + override fun onCues(cueGroup: CueGroup) { + super.onCues(cueGroup) + if (!shouldSendCaptionsToJS) return + val ccText = cueGroup.cues.firstOrNull()?.text?.toString() + sendHLSPlayerCuesEventToJS(ccText) + } }, ) } @@ -204,6 +217,38 @@ class HMSHLSPlayer(context: ReactContext) : FrameLayout(context) { hmsHlsPlayer?.volume = level } + fun areClosedCaptionSupported(requestId: Int) { + hmsHlsPlayer.let { + if (it == null) { + sendHLSDataRequestEventToJS(requestId, false) + } else { + sendHLSDataRequestEventToJS(requestId, it.areClosedCaptionsSupported()) + } + } + } + + fun isClosedCaptionEnabled(requestId: Int) { + sendHLSDataRequestEventToJS(requestId, shouldSendCaptionsToJS) + } + + fun enableClosedCaption() { + shouldSendCaptionsToJS = true + } + + fun disableClosedCaption() { + shouldSendCaptionsToJS = false + sendHLSPlayerCuesEventToJS(null) + } + + fun getPlayerDurationDetails(requestId: Int) { + val data: WritableMap = Arguments.createMap() + hmsHlsPlayer?.getNativePlayer()?.let { exoPlayer -> + data.putInt("rollingWindowTime", exoPlayer.seekParameters.toleranceAfterUs.div(1000).toInt()) + data.putInt("streamDuration", exoPlayer.duration.toInt()) + } + sendHLSDataRequestEventToJS(requestId, data) + } + fun enableStats(enable: Boolean) { if (enable) { attachStatsMonitor() @@ -215,11 +260,13 @@ class HMSHLSPlayer(context: ReactContext) : FrameLayout(context) { fun enableControls(show: Boolean) { playerView?.let { if (show) { + it.subtitleView?.visibility = View.VISIBLE it.useController = true it.showController() } else { it.hideController() it.useController = false + it.subtitleView?.visibility = View.GONE } } } @@ -263,6 +310,46 @@ class HMSHLSPlayer(context: ReactContext) : FrameLayout(context) { val reactContext = context as ReactContext reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, HMSHLSPlayerConstants.HMS_HLS_STATS_EVENT, event) } + + private fun sendHLSDataRequestEventToJS( + requestId: Int, + data: Any, + ) { + val event: WritableMap = Arguments.createMap() + event.putInt("requestId", requestId) + + if (data is Boolean) { + event.putBoolean("data", data) + } else if (data is String) { + event.putString("data", data) + } else if (data is Int) { + event.putInt("data", data) + } else if (data is Double) { + event.putDouble("data", data) + } else if (data is ReadableMap) { + event.putMap("data", data) + } else if (data is ReadableArray) { + event.putArray("data", data) + } else { + event.putNull("data") + } + + val reactContext = context as ReactContext + reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, HMSHLSPlayerConstants.HLS_DATA_REQUEST_EVENT, event) + } + + private fun sendHLSPlayerCuesEventToJS(ccText: String?) { + val event: WritableMap = Arguments.createMap() + event.putString("event", HMSHLSPlayerConstants.ON_CLOSED_CAPTION_UPDATE) + + if (ccText is String) { + event.putString("data", ccText) + } else { + event.putNull("data") + } + val reactContext = context as ReactContext + reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, HMSHLSPlayerConstants.HLS_PLAYER_CUES_EVENT, event) + } } object HMSHLSPlayerConstants { @@ -277,4 +364,11 @@ object HMSHLSPlayerConstants { const val HMS_HLS_STATS_EVENT = "hmsHlsStatsEvent" const val ON_STATS_EVENT_UPDATE = "ON_STATS_EVENT_UPDATE" const val ON_STATS_EVENT_ERROR = "ON_STATS_EVENT_ERROR" + + // HLS Requested Data Returned + const val HLS_DATA_REQUEST_EVENT = "hlsDataRequestEvent" + + // HLS Player Cues Events + const val HLS_PLAYER_CUES_EVENT = "hlsPlayerCuesEvent" + const val ON_CLOSED_CAPTION_UPDATE = "ON_CLOSED_CAPTION_UPDATE" } diff --git a/packages/react-native-hms/android/src/main/java/com/reactnativehmssdk/HMSHLSPlayerManager.kt b/packages/react-native-hms/android/src/main/java/com/reactnativehmssdk/HMSHLSPlayerManager.kt index e646d9ebf..4e7205caa 100644 --- a/packages/react-native-hms/android/src/main/java/com/reactnativehmssdk/HMSHLSPlayerManager.kt +++ b/packages/react-native-hms/android/src/main/java/com/reactnativehmssdk/HMSHLSPlayerManager.kt @@ -31,6 +31,10 @@ class HMSHLSPlayerManager : SimpleViewManager() { MapBuilder.of("registrationName", "onHmsHlsPlaybackEvent"), HMSHLSPlayerConstants.HMS_HLS_STATS_EVENT, MapBuilder.of("registrationName", "onHmsHlsStatsEvent"), + HMSHLSPlayerConstants.HLS_DATA_REQUEST_EVENT, + MapBuilder.of("registrationName", "onDataReturned"), + HMSHLSPlayerConstants.HLS_PLAYER_CUES_EVENT, + MapBuilder.of("registrationName", "onHlsPlayerCuesEvent"), ) } @@ -68,6 +72,29 @@ class HMSHLSPlayerManager : SimpleViewManager() { } } } + 90 -> { + args.let { + if (it != null) { + root.areClosedCaptionSupported(it.getInt(0)) + } + } + } + 100 -> { + args.let { + if (it != null) { + root.isClosedCaptionEnabled(it.getInt(0)) + } + } + } + 110 -> root.enableClosedCaption() + 120 -> root.disableClosedCaption() + 130 -> { + args.let { + if (it != null) { + root.getPlayerDurationDetails(it.getInt(0)) + } + } + } } } @@ -81,6 +108,11 @@ class HMSHLSPlayerManager : SimpleViewManager() { .put("seekForward", 60) .put("seekBackward", 70) .put("setVolume", 80) + .put("areClosedCaptionSupported", 90) + .put("isClosedCaptionEnabled", 100) + .put("enableClosedCaption", 110) + .put("disableClosedCaption", 120) + .put("getPlayerDurationDetails", 130) .build() } diff --git a/packages/react-native-hms/example/android/Gemfile.lock b/packages/react-native-hms/example/android/Gemfile.lock index fe1eace03..6736ac7a5 100644 --- a/packages/react-native-hms/example/android/Gemfile.lock +++ b/packages/react-native-hms/example/android/Gemfile.lock @@ -10,17 +10,17 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.904.0) - aws-sdk-core (3.191.5) + aws-partitions (1.916.0) + aws-sdk-core (3.192.1) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.78.0) + aws-sdk-kms (1.79.0) aws-sdk-core (~> 3, >= 3.191.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.146.1) - aws-sdk-core (~> 3, >= 3.191.0) + aws-sdk-s3 (1.147.0) + aws-sdk-core (~> 3, >= 3.192.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) aws-sigv4 (1.8.0) @@ -67,7 +67,7 @@ GEM faraday-retry (1.0.3) faraday_middleware (1.2.0) faraday (~> 1.0) - fastimage (2.3.0) + fastimage (2.3.1) fastlane (2.218.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) @@ -112,7 +112,7 @@ GEM google-apis-firebaseappdistribution_v1 (~> 0.3.0) google-apis-firebaseappdistribution_v1alpha (~> 0.2.0) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.60.0) + google-apis-androidpublisher_v3 (0.62.0) google-apis-core (>= 0.14.0, < 2.a) google-apis-core (0.14.1) addressable (~> 2.5, >= 2.5.1) @@ -138,12 +138,12 @@ GEM google-cloud-env (2.1.1) faraday (>= 1.0, < 3.a) google-cloud-errors (1.4.0) - google-cloud-storage (1.49.0) + google-cloud-storage (1.50.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-core (~> 0.13) google-apis-iamcredentials_v1 (~> 0.18) - google-apis-storage_v1 (~> 0.33) + google-apis-storage_v1 (~> 0.37) google-cloud-core (~> 1.6) googleauth (~> 1.9) mini_mime (~> 1.0) @@ -159,7 +159,7 @@ GEM domain_name (~> 0.5) httpclient (2.8.3) jmespath (1.6.2) - json (2.7.1) + json (2.7.2) jwt (2.8.1) base64 mini_magick (4.12.0) @@ -169,11 +169,11 @@ GEM nanaimo (0.3.0) naturally (2.2.1) nkf (0.2.0) - optparse (0.4.0) + optparse (0.5.0) os (1.1.4) plist (3.7.1) - public_suffix (5.0.4) - rake (13.1.0) + public_suffix (5.0.5) + rake (13.2.1) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) diff --git a/packages/react-native-hms/example/ios/Gemfile.lock b/packages/react-native-hms/example/ios/Gemfile.lock index 224f71e56..dc3eefeed 100644 --- a/packages/react-native-hms/example/ios/Gemfile.lock +++ b/packages/react-native-hms/example/ios/Gemfile.lock @@ -10,17 +10,17 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.904.0) - aws-sdk-core (3.191.5) + aws-partitions (1.916.0) + aws-sdk-core (3.192.1) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.78.0) + aws-sdk-kms (1.79.0) aws-sdk-core (~> 3, >= 3.191.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.146.1) - aws-sdk-core (~> 3, >= 3.191.0) + aws-sdk-s3 (1.147.0) + aws-sdk-core (~> 3, >= 3.192.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) aws-sigv4 (1.8.0) @@ -67,7 +67,7 @@ GEM faraday-retry (1.0.3) faraday_middleware (1.2.0) faraday (~> 1.0) - fastimage (2.3.0) + fastimage (2.3.1) fastlane (2.218.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) @@ -109,7 +109,7 @@ GEM xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.60.0) + google-apis-androidpublisher_v3 (0.62.0) google-apis-core (>= 0.14.0, < 2.a) google-apis-core (0.14.1) addressable (~> 2.5, >= 2.5.1) @@ -131,12 +131,12 @@ GEM google-cloud-env (2.1.1) faraday (>= 1.0, < 3.a) google-cloud-errors (1.4.0) - google-cloud-storage (1.49.0) + google-cloud-storage (1.50.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-core (~> 0.13) google-apis-iamcredentials_v1 (~> 0.18) - google-apis-storage_v1 (~> 0.33) + google-apis-storage_v1 (~> 0.37) google-cloud-core (~> 1.6) googleauth (~> 1.9) mini_mime (~> 1.0) @@ -152,7 +152,7 @@ GEM domain_name (~> 0.5) httpclient (2.8.3) jmespath (1.6.2) - json (2.7.1) + json (2.7.2) jwt (2.8.1) base64 mini_magick (4.12.0) @@ -162,11 +162,11 @@ GEM nanaimo (0.3.0) naturally (2.2.1) nkf (0.2.0) - optparse (0.4.0) + optparse (0.5.0) os (1.1.4) plist (3.7.1) - public_suffix (5.0.4) - rake (13.1.0) + public_suffix (5.0.5) + rake (13.2.1) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) diff --git a/packages/react-native-hms/example/ios/Podfile.lock b/packages/react-native-hms/example/ios/Podfile.lock index 36ae711e7..8383830cf 100644 --- a/packages/react-native-hms/example/ios/Podfile.lock +++ b/packages/react-native-hms/example/ios/Podfile.lock @@ -293,7 +293,7 @@ PODS: - React-Core - react-native-document-picker (8.2.2): - React-Core - - react-native-hms (1.10.2): + - react-native-hms (1.10.4): - HMSBroadcastExtensionSDK (= 0.0.9) - HMSHLSPlayerSDK (= 0.0.2) - HMSNoiseCancellationModels (= 1.0.0) @@ -653,7 +653,7 @@ SPEC CHECKSUMS: react-native-avoid-softinput: 71a692888f0c1d426ad9045dc8325773583962cd react-native-camera: 3eae183c1d111103963f3dd913b65d01aef8110f react-native-document-picker: cd4d6b36a5207ad7a9e599ebb9eb0c2e84fa0b87 - react-native-hms: f2eb84b87cf8468fdfb1bdd344f69e6e4bc56526 + react-native-hms: e930a8af433e469d7f9f5b5dc55a76ad155d787f react-native-safe-area-context: 9e40fb181dac02619414ba1294d6c2a807056ab9 react-native-simple-toast: 8ee5d23f0b92b935ab7434cdb65159ce12dfb4b7 React-perflogger: 5a890ca0911669421b7611661e9b58f91c805f5c diff --git a/packages/react-native-hms/example/package-lock.json b/packages/react-native-hms/example/package-lock.json index 18fabbff4..dad37b3e3 100644 --- a/packages/react-native-hms/example/package-lock.json +++ b/packages/react-native-hms/example/package-lock.json @@ -1,12 +1,12 @@ { "name": "RNHMSExample", - "version": "1.10.3", + "version": "1.10.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "RNHMSExample", - "version": "1.10.3", + "version": "1.10.4", "hasInstallScript": true, "dependencies": { "@miblanchard/react-native-slider": "^2.0.2", @@ -86,25 +86,25 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz", - "integrity": "sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.3.tgz", - "integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.1", + "@babel/generator": "^7.24.4", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.1", - "@babel/parser": "^7.24.1", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", "@babel/template": "^7.24.0", "@babel/traverse": "^7.24.1", "@babel/types": "^7.24.0", @@ -123,9 +123,9 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", - "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", "dependencies": { "@babel/types": "^7.24.0", "@jridgewell/gen-mapping": "^0.3.5", @@ -174,9 +174,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.1.tgz", - "integrity": "sha512-1yJa9dX9g//V6fDebXoEfEsxkZHk3Hcbm+zLhyu6qVgYFLvmTALTeV+jNU9e5RnYtioBrGEOdoI2joMSNQ/+aA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz", + "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", @@ -421,9 +421,9 @@ } }, "node_modules/@babel/helpers": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz", - "integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", "dependencies": { "@babel/template": "^7.24.0", "@babel/traverse": "^7.24.1", @@ -448,9 +448,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", - "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -458,6 +458,22 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz", + "integrity": "sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA==", + "peer": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.24.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", @@ -972,9 +988,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.1.tgz", - "integrity": "sha512-h71T2QQvDgM2SmT29UYU6ozjMlAt7s7CSs5Hvy8f8cf/GM/Z4a2zMfN+fjVGaieeCrXR3EdQl6C4gQG+OgmbKw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz", + "integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -1002,12 +1018,12 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.1.tgz", - "integrity": "sha512-FUHlKCn6J3ERiu8Dv+4eoz7w8+kFLSyeVG4vDAikwADGjUCoHw/JHokyGtr8OR4UjpwPVivyF+h8Q5iv/JmrtA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz", + "integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==", "peer": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-create-class-features-plugin": "^7.24.4", "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, @@ -1705,12 +1721,12 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.1.tgz", - "integrity": "sha512-liYSESjX2fZ7JyBFkYG78nfvHlMKE6IpNdTVnxmlYUR+j5ZLsitFbaAE+eJSK2zPPkNWNw4mXL51rQ8WrvdK0w==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.4.tgz", + "integrity": "sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-create-class-features-plugin": "^7.24.4", "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-typescript": "^7.24.1" }, @@ -1784,15 +1800,16 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.3.tgz", - "integrity": "sha512-fSk430k5c2ff8536JcPvPWK4tZDwehWLGlBp0wrsBUjZVdeQV6lePbwKWZaZfK2vnh/1kQX1PzAJWsnBmVgGJA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.4.tgz", + "integrity": "sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A==", "peer": true, "dependencies": { - "@babel/compat-data": "^7.24.1", + "@babel/compat-data": "^7.24.4", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.4", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1", @@ -1819,9 +1836,9 @@ "@babel/plugin-transform-async-generator-functions": "^7.24.3", "@babel/plugin-transform-async-to-generator": "^7.24.1", "@babel/plugin-transform-block-scoped-functions": "^7.24.1", - "@babel/plugin-transform-block-scoping": "^7.24.1", + "@babel/plugin-transform-block-scoping": "^7.24.4", "@babel/plugin-transform-class-properties": "^7.24.1", - "@babel/plugin-transform-class-static-block": "^7.24.1", + "@babel/plugin-transform-class-static-block": "^7.24.4", "@babel/plugin-transform-classes": "^7.24.1", "@babel/plugin-transform-computed-properties": "^7.24.1", "@babel/plugin-transform-destructuring": "^7.24.1", @@ -1969,9 +1986,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", - "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", + "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -3802,9 +3819,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.12.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.2.tgz", - "integrity": "sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==", + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "dependencies": { "undici-types": "~5.26.4" } @@ -4755,19 +4772,16 @@ } }, "node_modules/babel-plugin-module-resolver": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.0.tgz", - "integrity": "sha512-g0u+/ChLSJ5+PzYwLwP8Rp8Rcfowz58TJNCe+L/ui4rpzE/mg//JVX0EWBUYoxaextqnwuGHzfGp2hh0PPV25Q==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.2.tgz", + "integrity": "sha512-9KtaCazHee2xc0ibfqsDeamwDps6FZNo5S0Q81dUqEuFzVwPhcT4J5jOqIVvgCA3Q/wO9hKYxN/Ds3tIsp5ygg==", "dev": true, "dependencies": { - "find-babel-config": "^2.0.0", - "glob": "^8.0.3", + "find-babel-config": "^2.1.1", + "glob": "^9.3.3", "pkg-up": "^3.1.0", "reselect": "^4.1.7", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">= 16" + "resolve": "^1.22.8" } }, "node_modules/babel-plugin-module-resolver/node_modules/brace-expansion": { @@ -4780,34 +4794,36 @@ } }, "node_modules/babel-plugin-module-resolver/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/babel-plugin-module-resolver/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/babel-plugin-polyfill-corejs2": { @@ -5175,9 +5191,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001603", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001603.tgz", - "integrity": "sha512-iL2iSS0eDILMb9n5yKQoTBim9jMZ0Yrk8g0N9K7UzYyWnfIKzXBZD5ngpM37ZcL/cv0Mli8XtVMRYMQAfFpi5Q==", + "version": "1.0.30001612", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", + "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", "funding": [ { "type": "opencollective", @@ -5511,9 +5527,9 @@ } }, "node_modules/core-js-compat": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", - "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz", + "integrity": "sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==", "dependencies": { "browserslist": "^4.23.0" }, @@ -5881,9 +5897,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.722", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.722.tgz", - "integrity": "sha512-5nLE0TWFFpZ80Crhtp4pIp8LXCztjYX41yUcV6b+bKR2PqzjskTMOOlBi1VjBHlvHwS+4gar7kNKOrsbsewEZQ==" + "version": "1.4.745", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.745.tgz", + "integrity": "sha512-tRbzkaRI5gbUn5DEvF0dV4TQbMZ5CLkWeTAXmpC9IrYT+GE+x76i9p+o3RJ5l9XmdQlI1pPhVtE9uNcJJ0G0EA==" }, "node_modules/emittery": { "version": "0.7.2", @@ -5932,9 +5948,9 @@ } }, "node_modules/envinfo": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz", - "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.12.0.tgz", + "integrity": "sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==", "bin": { "envinfo": "dist/cli.js" }, @@ -7033,16 +7049,13 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/find-babel-config": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-2.0.0.tgz", - "integrity": "sha512-dOKT7jvF3hGzlW60Gc3ONox/0rRZ/tz7WCil0bqA1In/3I8f1BctpXahRnEKDySZqci7u+dqq93sZST9fOJpFw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-2.1.1.tgz", + "integrity": "sha512-5Ji+EAysHGe1OipH7GN4qDjok5Z1uw5KAwDCbicU/4wyTZY7CqOCzcWbG7J5ad9mazq67k89fXlbc1MuIfl9uA==", "dev": true, "dependencies": { - "json5": "^2.1.1", + "json5": "^2.2.3", "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" } }, "node_modules/find-cache-dir": { @@ -10045,9 +10058,9 @@ } }, "node_modules/joi": { - "version": "17.12.2", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.2.tgz", - "integrity": "sha512-RonXAIzCiHLc8ss3Ibuz45u28GOsWE1UpfDXLbN/9NKbL4tCJf8TWYVKsoYuuh+sAUt7fsSNpA+r2+TBA6Wjmw==", + "version": "17.12.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.3.tgz", + "integrity": "sha512-2RRziagf555owrm9IRVtdKynOBeITiDpuZqIpgwqXShPncPKNiRQoiGsl/T8SQdq+8ugRzH2LqY67irr2y/d+g==", "dependencies": { "@hapi/hoek": "^9.3.0", "@hapi/topo": "^5.1.0", @@ -11163,6 +11176,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -11430,9 +11452,9 @@ "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==" }, "node_modules/nwsapi": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", - "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz", + "integrity": "sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==", "dev": true }, "node_modules/ob1": { @@ -11877,6 +11899,40 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-scurry": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", diff --git a/packages/react-native-hms/example/package.json b/packages/react-native-hms/example/package.json index f7f2557a3..2faeba5eb 100644 --- a/packages/react-native-hms/example/package.json +++ b/packages/react-native-hms/example/package.json @@ -1,6 +1,6 @@ { "name": "RNHMSExample", - "version": "1.10.3", + "version": "1.10.4", "private": true, "scripts": { "preinstall": "cd ../ && npm install && cd ./example", diff --git a/packages/react-native-hms/ios/HMSDecoder.swift b/packages/react-native-hms/ios/HMSDecoder.swift index 1dfdef40d..c411ea8a2 100644 --- a/packages/react-native-hms/ios/HMSDecoder.swift +++ b/packages/react-native-hms/ios/HMSDecoder.swift @@ -811,12 +811,24 @@ class HMSDecoder: NSObject { if let startedAt = variant.startedAt?.timeIntervalSince1970 { decodedVariant["startedAt"] = startedAt * 1000 } + if let type = variant.playlistType { + decodedVariant["playlistType"] = getHLSVariantPlaylistType(from: type) + } variants.append(decodedVariant) } } return variants } + static func getHLSVariantPlaylistType(from type: HMSHLSPlaylistType) -> String { + switch type { + case .dvr: + return "DVR" + default: + return "NODVR" + } + } + static func getHMSRTCStats(_ data: HMSRTCStats) -> [Any] { // [bitrateReceived, bitrateSent, bytesReceived, bytesSent, packetsLost, packetsReceived, roundTripTime] return [ diff --git a/packages/react-native-hms/ios/HMSHLSPlayerManager.m b/packages/react-native-hms/ios/HMSHLSPlayerManager.m index 064f95a6c..f1ad26821 100644 --- a/packages/react-native-hms/ios/HMSHLSPlayerManager.m +++ b/packages/react-native-hms/ios/HMSHLSPlayerManager.m @@ -7,6 +7,7 @@ @interface RCT_EXTERN_MODULE(HMSHLSPlayerManager, RCTViewManager) RCT_EXPORT_VIEW_PROPERTY(url, NSString); RCT_EXPORT_VIEW_PROPERTY(enableStats, BOOL); RCT_EXPORT_VIEW_PROPERTY(enableControls, BOOL); +RCT_EXPORT_VIEW_PROPERTY(onDataReturned, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onHmsHlsPlaybackEvent, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onHmsHlsStatsEvent, RCTDirectEventBlock); @@ -18,5 +19,10 @@ @interface RCT_EXTERN_MODULE(HMSHLSPlayerManager, RCTViewManager) RCT_EXTERN_METHOD(seekForward:(nonnull NSNumber *)node seconds:(nonnull NSNumber *)seconds) RCT_EXTERN_METHOD(seekBackward:(nonnull NSNumber *)node seconds:(nonnull NSNumber *)seconds) RCT_EXTERN_METHOD(setVolume:(nonnull NSNumber *)node level:(nonnull NSNumber *)level) +RCT_EXTERN_METHOD(areClosedCaptionSupported:(nonnull NSNumber *)node requestId:(nonnull NSNumber *)requestId) +RCT_EXTERN_METHOD(isClosedCaptionEnabled:(nonnull NSNumber *)node requestId:(nonnull NSNumber *)requestId) +RCT_EXTERN_METHOD(enableClosedCaption:(nonnull NSNumber *)node) +RCT_EXTERN_METHOD(disableClosedCaption:(nonnull NSNumber *)node) +RCT_EXTERN_METHOD(getPlayerDurationDetails:(nonnull NSNumber *)node requestId:(nonnull NSNumber *)requestId) @end diff --git a/packages/react-native-hms/ios/HMSHLSPlayerManager.swift b/packages/react-native-hms/ios/HMSHLSPlayerManager.swift index 2ce23e741..0ec9f5df8 100644 --- a/packages/react-native-hms/ios/HMSHLSPlayerManager.swift +++ b/packages/react-native-hms/ios/HMSHLSPlayerManager.swift @@ -87,6 +87,46 @@ class HMSHLSPlayerManager: RCTViewManager { } } } + + @objc func areClosedCaptionSupported(_ node: NSNumber, requestId: NSNumber) { + DispatchQueue.main.async { + if let component = self.bridge.uiManager.view(forReactTag: node) as? HMSHLSPlayer { + component.areClosedCaptionSupported(requestId: UInt(truncating: requestId)) + } + } + } + + @objc func isClosedCaptionEnabled(_ node: NSNumber, requestId: NSNumber) { + DispatchQueue.main.async { + if let component = self.bridge.uiManager.view(forReactTag: node) as? HMSHLSPlayer { + component.isClosedCaptionEnabled(requestId: UInt(truncating: requestId)) + } + } + } + + @objc func enableClosedCaption(_ node: NSNumber) { + DispatchQueue.main.async { + if let component = self.bridge.uiManager.view(forReactTag: node) as? HMSHLSPlayer { + component.enableClosedCaption() + } + } + } + + @objc func disableClosedCaption(_ node: NSNumber) { + DispatchQueue.main.async { + if let component = self.bridge.uiManager.view(forReactTag: node) as? HMSHLSPlayer { + component.disableClosedCaption() + } + } + } + + @objc func getPlayerDurationDetails(_ node: NSNumber, requestId: NSNumber) { + DispatchQueue.main.async { + if let component = self.bridge.uiManager.view(forReactTag: node) as? HMSHLSPlayer { + component.getPlayerDurationDetails(requestId: UInt(truncating: requestId)) + } + } + } } class HMSHLSPlayer: UIView { @@ -105,6 +145,8 @@ class HMSHLSPlayer: UIView { // MARK: Handle HMSHLSPlayer RN Component props + @objc var onDataReturned: RCTDirectEventBlock? + @objc var onHmsHlsPlaybackEvent: RCTDirectEventBlock? @objc var onHmsHlsStatsEvent: RCTDirectEventBlock? @@ -158,6 +200,97 @@ class HMSHLSPlayer: UIView { hmsHLSPlayer.stop() } + private func isCCSupported() -> Bool { + guard let playerItem = hmsHLSPlayer._nativePlayer.currentItem else { + return false + } + guard let mediaSelectionGroup = playerItem.asset.mediaSelectionGroup(forMediaCharacteristic: .legible) else { + return false + } + guard let firstMediaSelectionGroupOption = mediaSelectionGroup.options.first else { + return false + } + return firstMediaSelectionGroupOption.mediaType == .subtitle + } + + private func isCCEnabled() -> Bool { + guard let playerItem = hmsHLSPlayer._nativePlayer.currentItem else { + return false + } + guard let subtitle = playerItem.asset.mediaSelectionGroup(forMediaCharacteristic: .legible) else { + return false + } + let selectedOption = playerItem.currentMediaSelection.selectedMediaOption(in: subtitle) + return selectedOption != nil + } + + @objc func areClosedCaptionSupported(requestId: UInt) { + let supported = isCCSupported() + + sendRequestedDataToJS(requestId, supported) + } + + @objc func isClosedCaptionEnabled(requestId: UInt) { + let enabled = isCCEnabled() + + sendRequestedDataToJS(requestId, enabled) + } + + @objc func enableClosedCaption() { + if !isCCSupported() { + print("#func Closed Caption is not supported") + return + } + if isCCEnabled() { + print("#func Closed Caption already enabled!") + return + } + guard let playerItem = hmsHLSPlayer._nativePlayer.currentItem else { + return + } + guard let subtitle = playerItem.asset.mediaSelectionGroup(forMediaCharacteristic: .legible) else { + return + } + guard let firstSubtitleTrack = subtitle.options.first(where: {$0.mediaType == .subtitle}) else { + return + } + playerItem.select(firstSubtitleTrack, in: subtitle) + } + + @objc func disableClosedCaption() { + if !isCCSupported() { + print("#func Closed Caption is not supported") + return + } + if !isCCEnabled() { + print("#func Closed Caption already disabled!") + return + } + guard let playerItem = hmsHLSPlayer._nativePlayer.currentItem else { + return + } + guard let subtitle = playerItem.asset.mediaSelectionGroup(forMediaCharacteristic: .legible) else { + return + } + playerItem.select(nil, in: subtitle) + } + + @objc func getPlayerDurationDetails(requestId: UInt) { + var map = [String: Any?]() + guard let playerItem = hmsHLSPlayer._nativePlayer.currentItem else { + sendRequestedDataToJS(requestId, map) + return + } + // If duration is known + if !playerItem.duration.isIndefinite { + map["streamDuration"] = playerItem.duration.seconds + } + if let timeRange = playerItem.seekableTimeRanges.last as? CMTimeRange { + map["rollingWindowTime"] = timeRange.duration.seconds * 1000 + } + sendRequestedDataToJS(requestId, map) + } + @objc func pause() { hmsHLSPlayer.pause() } @@ -182,7 +315,7 @@ class HMSHLSPlayer: UIView { hmsHLSPlayer.volume = level } - // MARK: Constructor & Deconstructor + // MARK: Lifecycle methods override init(frame: CGRect) { super.init(frame: frame) @@ -234,6 +367,12 @@ class HMSHLSPlayer: UIView { onHmsHlsPlaybackEvent(["event": eventName, "data": data]) } + private func sendRequestedDataToJS(_ requestId: UInt, _ data: Any) { + guard let onDataReturned = onDataReturned else { return } + + onDataReturned(["requestId": requestId, "data": data]) + } + private func sendHLSStatsEventToJS(_ eventName: String, _ data: [String: Any]) { guard let onHmsHlsStatsEvent = onHmsHlsStatsEvent else { return } diff --git a/packages/react-native-hms/package-lock.json b/packages/react-native-hms/package-lock.json index e245843db..47cbf74ef 100644 --- a/packages/react-native-hms/package-lock.json +++ b/packages/react-native-hms/package-lock.json @@ -1,12 +1,12 @@ { "name": "@100mslive/react-native-hms", - "version": "1.10.3", + "version": "1.10.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@100mslive/react-native-hms", - "version": "1.10.3", + "version": "1.10.4", "license": "MIT", "dependencies": { "zustand": "^4.3.8" @@ -71,27 +71,27 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz", - "integrity": "sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.3.tgz", - "integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.1", + "@babel/generator": "^7.24.4", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.1", - "@babel/parser": "^7.24.1", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", "@babel/template": "^7.24.0", "@babel/traverse": "^7.24.1", "@babel/types": "^7.24.0", @@ -125,9 +125,9 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", - "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", "dev": true, "dependencies": { "@babel/types": "^7.24.0", @@ -189,9 +189,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.1.tgz", - "integrity": "sha512-1yJa9dX9g//V6fDebXoEfEsxkZHk3Hcbm+zLhyu6qVgYFLvmTALTeV+jNU9e5RnYtioBrGEOdoI2joMSNQ/+aA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz", + "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", @@ -472,9 +472,9 @@ } }, "node_modules/@babel/helpers": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz", - "integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", "dev": true, "dependencies": { "@babel/template": "^7.24.0", @@ -501,9 +501,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", - "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -512,6 +512,22 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz", + "integrity": "sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.24.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", @@ -1050,9 +1066,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.1.tgz", - "integrity": "sha512-h71T2QQvDgM2SmT29UYU6ozjMlAt7s7CSs5Hvy8f8cf/GM/Z4a2zMfN+fjVGaieeCrXR3EdQl6C4gQG+OgmbKw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz", + "integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" @@ -1081,12 +1097,12 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.1.tgz", - "integrity": "sha512-FUHlKCn6J3ERiu8Dv+4eoz7w8+kFLSyeVG4vDAikwADGjUCoHw/JHokyGtr8OR4UjpwPVivyF+h8Q5iv/JmrtA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz", + "integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-create-class-features-plugin": "^7.24.4", "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, @@ -1848,13 +1864,13 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.1.tgz", - "integrity": "sha512-liYSESjX2fZ7JyBFkYG78nfvHlMKE6IpNdTVnxmlYUR+j5ZLsitFbaAE+eJSK2zPPkNWNw4mXL51rQ8WrvdK0w==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.4.tgz", + "integrity": "sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-create-class-features-plugin": "^7.24.4", "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-typescript": "^7.24.1" }, @@ -1929,15 +1945,16 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.3.tgz", - "integrity": "sha512-fSk430k5c2ff8536JcPvPWK4tZDwehWLGlBp0wrsBUjZVdeQV6lePbwKWZaZfK2vnh/1kQX1PzAJWsnBmVgGJA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.4.tgz", + "integrity": "sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.24.1", + "@babel/compat-data": "^7.24.4", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.4", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1", @@ -1964,9 +1981,9 @@ "@babel/plugin-transform-async-generator-functions": "^7.24.3", "@babel/plugin-transform-async-to-generator": "^7.24.1", "@babel/plugin-transform-block-scoped-functions": "^7.24.1", - "@babel/plugin-transform-block-scoping": "^7.24.1", + "@babel/plugin-transform-block-scoping": "^7.24.4", "@babel/plugin-transform-class-properties": "^7.24.1", - "@babel/plugin-transform-class-static-block": "^7.24.1", + "@babel/plugin-transform-class-static-block": "^7.24.4", "@babel/plugin-transform-classes": "^7.24.1", "@babel/plugin-transform-computed-properties": "^7.24.1", "@babel/plugin-transform-destructuring": "^7.24.1", @@ -2149,9 +2166,9 @@ "dev": true }, "node_modules/@babel/runtime": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", - "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", + "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -4673,9 +4690,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.12.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.2.tgz", - "integrity": "sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==", + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -6046,9 +6063,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001603", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001603.tgz", - "integrity": "sha512-iL2iSS0eDILMb9n5yKQoTBim9jMZ0Yrk8g0N9K7UzYyWnfIKzXBZD5ngpM37ZcL/cv0Mli8XtVMRYMQAfFpi5Q==", + "version": "1.0.30001612", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", + "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", "dev": true, "funding": [ { @@ -6492,9 +6509,9 @@ } }, "node_modules/core-js": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.36.1.tgz", - "integrity": "sha512-BTvUrwxVBezj5SZ3f10ImnX2oRByMxql3EimVqMysepbC9EeMUOpLwdy6Eoili2x6E4kf+ZUB5k/+Jv55alPfA==", + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.0.tgz", + "integrity": "sha512-fu5vHevQ8ZG4og+LXug8ulUtVxjOcEYvifJr7L5Bfq9GOztVqsKd9/59hUk2ZSbCrS3BqUr3EpaYGIYzq7g3Ug==", "dev": true, "hasInstallScript": true, "funding": { @@ -6503,9 +6520,9 @@ } }, "node_modules/core-js-compat": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", - "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz", + "integrity": "sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==", "dev": true, "dependencies": { "browserslist": "^4.23.0" @@ -6946,9 +6963,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.722", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.722.tgz", - "integrity": "sha512-5nLE0TWFFpZ80Crhtp4pIp8LXCztjYX41yUcV6b+bKR2PqzjskTMOOlBi1VjBHlvHwS+4gar7kNKOrsbsewEZQ==", + "version": "1.4.745", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.745.tgz", + "integrity": "sha512-tRbzkaRI5gbUn5DEvF0dV4TQbMZ5CLkWeTAXmpC9IrYT+GE+x76i9p+o3RJ5l9XmdQlI1pPhVtE9uNcJJ0G0EA==", "dev": true }, "node_modules/emittery": { @@ -7001,9 +7018,9 @@ } }, "node_modules/envinfo": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz", - "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.12.0.tgz", + "integrity": "sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==", "dev": true, "bin": { "envinfo": "dist/cli.js" @@ -11555,9 +11572,9 @@ } }, "node_modules/joi": { - "version": "17.12.2", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.2.tgz", - "integrity": "sha512-RonXAIzCiHLc8ss3Ibuz45u28GOsWE1UpfDXLbN/9NKbL4tCJf8TWYVKsoYuuh+sAUt7fsSNpA+r2+TBA6Wjmw==", + "version": "17.12.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.3.tgz", + "integrity": "sha512-2RRziagf555owrm9IRVtdKynOBeITiDpuZqIpgwqXShPncPKNiRQoiGsl/T8SQdq+8ugRzH2LqY67irr2y/d+g==", "dev": true, "dependencies": { "@hapi/hoek": "^9.3.0", @@ -13145,9 +13162,9 @@ "dev": true }, "node_modules/nwsapi": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", - "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz", + "integrity": "sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==", "dev": true }, "node_modules/ob1": { diff --git a/packages/react-native-hms/package.json b/packages/react-native-hms/package.json index 41ee1da5d..74878d3e4 100644 --- a/packages/react-native-hms/package.json +++ b/packages/react-native-hms/package.json @@ -1,6 +1,6 @@ { "name": "@100mslive/react-native-hms", - "version": "1.10.3", + "version": "1.10.4", "description": "Integrate Real Time Audio and Video conferencing, Interactive Live Streaming, and Chat in your apps with 100ms React Native SDK. With support for HLS and RTMP Live Streaming and Recording, Picture-in-Picture (PiP), one-to-one Video Call Modes, Audio Rooms, Video Player and much more, add immersive real-time communications to your apps.", "main": "lib/commonjs/index", "module": "lib/module/index", diff --git a/packages/react-native-hms/sdk-versions.json b/packages/react-native-hms/sdk-versions.json index 4ba2c0ee4..0da94f60f 100644 --- a/packages/react-native-hms/sdk-versions.json +++ b/packages/react-native-hms/sdk-versions.json @@ -1,7 +1,7 @@ { - "ios": "1.8.0", + "ios": "1.9.0", "iOSBroadcastExtension": "0.0.9", "iOSHMSHLSPlayer": "0.0.2", "iOSNoiseCancellationModels": "1.0.0", - "android": "2.9.53" + "android": "2.9.54" } diff --git a/packages/react-native-hms/src/classes/HMSEncoder.ts b/packages/react-native-hms/src/classes/HMSEncoder.ts index 511556dad..c0295d127 100644 --- a/packages/react-native-hms/src/classes/HMSEncoder.ts +++ b/packages/react-native-hms/src/classes/HMSEncoder.ts @@ -40,6 +40,7 @@ import { HMSLayer } from './HMSLayer'; import { HMSSimulcastLayerDefinition } from './HMSSimulcastLayerDefinition'; import { HMSQualityLimitationReasons } from './HMSQualityLimitationReasons'; import { HMSTrackType } from './HMSTrackType'; +import { HMSHLSPlaylistType } from './HMSHLSPlaylistType'; interface InitialData { roles: Record; @@ -520,6 +521,9 @@ export class HMSEncoder { meetingUrl: item.meetingUrl, metadata: item?.metaData ? item?.metadata : undefined, startedAt: HMSEncoder.encodeDate(item?.startedAt), + playlistType: item?.playlistType + ? this.getHLSVariantPlaylistType(item.playlistType.toUpperCase()) + : undefined, }); variants.push(variant); }); @@ -527,6 +531,15 @@ export class HMSEncoder { return variants; } + static getHLSVariantPlaylistType(type: String) { + switch (type) { + case 'DVR': + return HMSHLSPlaylistType.DVR; + default: + return HMSHLSPlaylistType.noDVR; + } + } + static encodeHMSNetworkQuality(data: any) { if (data) { return new HMSNetworkQuality({ diff --git a/packages/react-native-hms/src/classes/HMSHLSPlaylistType.ts b/packages/react-native-hms/src/classes/HMSHLSPlaylistType.ts new file mode 100644 index 000000000..47d27c397 --- /dev/null +++ b/packages/react-native-hms/src/classes/HMSHLSPlaylistType.ts @@ -0,0 +1,4 @@ +export enum HMSHLSPlaylistType { + DVR = 'DVR', + noDVR = 'noDVR', +} diff --git a/packages/react-native-hms/src/classes/HMSHLSVariant.ts b/packages/react-native-hms/src/classes/HMSHLSVariant.ts index 9c8d8637d..eb68e603c 100644 --- a/packages/react-native-hms/src/classes/HMSHLSVariant.ts +++ b/packages/react-native-hms/src/classes/HMSHLSVariant.ts @@ -1,18 +1,23 @@ +import type { HMSHLSPlaylistType } from './HMSHLSPlaylistType'; + export class HMSHLSVariant { hlsStreamUrl?: string; meetingUrl?: string; metadata?: string; startedAt?: Date; + playlistType?: HMSHLSPlaylistType; constructor(params: { hlsStreamUrl?: string; meetingUrl?: string; metadata?: string; startedAt?: Date; + playlistType?: HMSHLSPlaylistType; }) { this.hlsStreamUrl = params.hlsStreamUrl; this.meetingUrl = params.meetingUrl; this.metadata = params.metadata; this.startedAt = params.startedAt; + this.playlistType = params.playlistType; } } diff --git a/packages/react-native-hms/src/classes/HMSNoiseCancellationPlugin.ts b/packages/react-native-hms/src/classes/HMSNoiseCancellationPlugin.ts index d853998ae..96e98fe99 100644 --- a/packages/react-native-hms/src/classes/HMSNoiseCancellationPlugin.ts +++ b/packages/react-native-hms/src/classes/HMSNoiseCancellationPlugin.ts @@ -4,6 +4,7 @@ import { logger } from './HMSLogger'; /** * Class representing an HMS Noise Cancellation Plugin. + * Checkout {@link https://www.100ms.live/docs/react-native/v2/how-to-guides/extend-capabilities/noise-cancellation} for more info */ export class HMSNoiseCancellationPlugin { modelName: HMSNoiseCancellationModels; diff --git a/packages/react-native-hms/src/components/HMSHLSPlayer/HMSHLSPlayer.tsx b/packages/react-native-hms/src/components/HMSHLSPlayer/HMSHLSPlayer.tsx index 5132f6139..23556a462 100644 --- a/packages/react-native-hms/src/components/HMSHLSPlayer/HMSHLSPlayer.tsx +++ b/packages/react-native-hms/src/components/HMSHLSPlayer/HMSHLSPlayer.tsx @@ -1,5 +1,11 @@ -import React, { useImperativeHandle, useRef } from 'react'; -import { View, StyleSheet, UIManager, findNodeHandle } from 'react-native'; +import React, { useEffect, useImperativeHandle, useMemo, useRef } from 'react'; +import { + View, + StyleSheet, + UIManager, + findNodeHandle, + Platform, +} from 'react-native'; import type { StyleProp, ViewStyle } from 'react-native'; import { @@ -9,23 +15,31 @@ import { setHMSHLSPlayerResolution, setHMSHLSPlayerStats, setHMSHLSPlayerStatsError, + setHMSHLSPlayerSubtitles, } from './hooks'; import { RCTHMSHLSPlayer, RCTHMSHLSPlayerViewManagerConfig, } from './RCTHMSHLSPlayer'; import type { + HlsSPlayerCuesEventHandler, HmsHlsPlaybackEventHandler, HmsHlsStatsEventHandler, RCTHMSHLSPlayerRef, + RequestedDataEventHandler, } from './RCTHMSHLSPlayer'; import { HMSHLSPlayerPlaybackEventTypes, HMSHLSPlayerStatsEventTypes, } from '../../types'; -import type { HMSHLSPlayerPlaybackCueEventData } from '../../types'; +import type { + HLSPlayerDurationDetails, + HMSHLSPlayerPlaybackCueEventData, +} from '../../types'; import { HMSEncoder } from '../../classes/HMSEncoder'; import type { HMSHLSPlayerPlaybackCue } from '../../stores/types'; +import { useHMSStore } from '../../stores/hms-store'; +import { useHMSHLSPlayerStatsStore } from '../../stores/hls-player-stats-store'; export interface HMSHLSPlayerProps { url?: string; @@ -45,6 +59,11 @@ export interface HMSHLSPlayerRefProperties { seekBackward: (seconds: number) => void; seekToLivePosition: () => void; setVolume: (level: number) => void; + isClosedCaptionSupported: () => Promise; + isClosedCaptionEnabled: () => Promise; + enableClosedCaption: () => void; + disableClosedCaption: () => void; + getPlayerDurationDetails: () => Promise; } const _HMSHLSPlayer: React.ForwardRefRenderFunction< @@ -55,6 +74,15 @@ const _HMSHLSPlayer: React.ForwardRefRenderFunction< ref ) => { const hmsHlsPlayerRef = useRef(null); + const promiseAndIdsMap = useMemo( + () => + new Map< + number, + { resolve(value: unknown): void; reject(reason?: any): void } + >(), + [] + ); + const currentRequestId = useRef(1); useImperativeHandle( ref, @@ -177,8 +205,94 @@ const _HMSHLSPlayer: React.ForwardRefRenderFunction< ); } }, + isClosedCaptionSupported: () => { + if ( + hmsHlsPlayerRef.current && + RCTHMSHLSPlayerViewManagerConfig.Commands.areClosedCaptionSupported + ) { + const requestId = currentRequestId.current++; + const promise = new Promise((resolve, reject) => { + promiseAndIdsMap.set(requestId, { resolve, reject }); + }); + + UIManager.dispatchViewManagerCommand( + findNodeHandle(hmsHlsPlayerRef.current), + RCTHMSHLSPlayerViewManagerConfig.Commands.areClosedCaptionSupported, + [requestId] + ); + return promise; + } + return Promise.resolve(false); + }, + isClosedCaptionEnabled: () => { + if ( + hmsHlsPlayerRef.current && + RCTHMSHLSPlayerViewManagerConfig.Commands.isClosedCaptionEnabled + ) { + const requestId = currentRequestId.current++; + const promise = new Promise((resolve, reject) => { + promiseAndIdsMap.set(requestId, { resolve, reject }); + }); + + UIManager.dispatchViewManagerCommand( + findNodeHandle(hmsHlsPlayerRef.current), + RCTHMSHLSPlayerViewManagerConfig.Commands.isClosedCaptionEnabled, + [requestId] + ); + return promise; + } + return Promise.resolve(false); + }, + enableClosedCaption: () => { + if ( + hmsHlsPlayerRef.current && + RCTHMSHLSPlayerViewManagerConfig.Commands.enableClosedCaption + ) { + UIManager.dispatchViewManagerCommand( + findNodeHandle(hmsHlsPlayerRef.current), + RCTHMSHLSPlayerViewManagerConfig.Commands.enableClosedCaption, + undefined + ); + } + }, + disableClosedCaption: () => { + if ( + hmsHlsPlayerRef.current && + RCTHMSHLSPlayerViewManagerConfig.Commands.disableClosedCaption + ) { + UIManager.dispatchViewManagerCommand( + findNodeHandle(hmsHlsPlayerRef.current), + RCTHMSHLSPlayerViewManagerConfig.Commands.disableClosedCaption, + undefined + ); + } + }, + getPlayerDurationDetails: () => { + if ( + hmsHlsPlayerRef.current && + RCTHMSHLSPlayerViewManagerConfig.Commands.getPlayerDurationDetails + ) { + const requestId = currentRequestId.current++; + const promise = new Promise( + (resolve, reject) => { + promiseAndIdsMap.set(requestId, { resolve, reject }); + } + ); + + UIManager.dispatchViewManagerCommand( + findNodeHandle(hmsHlsPlayerRef.current), + RCTHMSHLSPlayerViewManagerConfig.Commands.getPlayerDurationDetails, + [requestId] + ); + return promise; + } + return Promise.resolve({ + streamDuration: undefined, + rollingWindowTime: undefined, + }); + }, }), - [] + [currentRequestId, promiseAndIdsMap] ); // Handle HLS Playback events @@ -218,6 +332,42 @@ const _HMSHLSPlayer: React.ForwardRefRenderFunction< } }; + // Handle HLS Player Cues events (e.g. usage - Closed Captions) + const handleHLSPlayerCuesEvent: HlsSPlayerCuesEventHandler = ({ + nativeEvent, + }) => { + const { event, data } = nativeEvent; + + if (event === 'ON_CLOSED_CAPTION_UPDATE') { + setHMSHLSPlayerSubtitles(data); + } + }; + + // Handle Requested data + const handleRequestedDataReturned: RequestedDataEventHandler = ({ + nativeEvent, + }) => { + const { requestId, data } = nativeEvent; + const promiseMethods = promiseAndIdsMap.get(requestId); + + if (!promiseMethods) { + console.warn( + '#function handleRequestedDataReturned', + "Didn't found promise methods by requestId: ", + requestId + ); + return; + } + promiseMethods.resolve(data); + }; + + useEffect(() => { + return () => { + useHMSStore.getState().resetPlaybackSlice(); + useHMSHLSPlayerStatsStore.getState().reset(); + }; + }, []); + return ( @@ -229,6 +379,10 @@ const _HMSHLSPlayer: React.ForwardRefRenderFunction< enableControls={enableControls} onHmsHlsPlaybackEvent={handleHLSPlaybackEvent} onHmsHlsStatsEvent={handleHLSStatsEvent} + onHlsPlayerCuesEvent={ + Platform.OS === 'android' ? handleHLSPlayerCuesEvent : undefined + } + onDataReturned={handleRequestedDataReturned} /> diff --git a/packages/react-native-hms/src/components/HMSHLSPlayer/RCTHMSHLSPlayer.ts b/packages/react-native-hms/src/components/HMSHLSPlayer/RCTHMSHLSPlayer.ts index 38fd5741a..2da326fd9 100644 --- a/packages/react-native-hms/src/components/HMSHLSPlayer/RCTHMSHLSPlayer.ts +++ b/packages/react-native-hms/src/components/HMSHLSPlayer/RCTHMSHLSPlayer.ts @@ -6,8 +6,10 @@ import type { NativeMethods, } from 'react-native'; import type { + HMSHLSPlayerCuesEvent, HMSHLSPlayerPlaybackEvent, HMSHLSPlayerStatsEvent, + RequestedDataEvent, } from '../../types'; export type HmsHlsPlaybackEventHandler = ( @@ -18,6 +20,14 @@ export type HmsHlsStatsEventHandler = ( event: NativeSyntheticEvent ) => void; +export type HlsSPlayerCuesEventHandler = ( + event: NativeSyntheticEvent +) => void; + +export type RequestedDataEventHandler = ( + event: NativeSyntheticEvent +) => void; + export type RCTHMSHLSPlayerProps = { url?: string; style?: StyleProp; @@ -25,6 +35,8 @@ export type RCTHMSHLSPlayerProps = { enableControls?: boolean; onHmsHlsPlaybackEvent?: HmsHlsPlaybackEventHandler; onHmsHlsStatsEvent?: HmsHlsStatsEventHandler; + onDataReturned?: RequestedDataEventHandler; + onHlsPlayerCuesEvent?: HlsSPlayerCuesEventHandler; }; export const RCTHMSHLSPlayer = diff --git a/packages/react-native-hms/src/components/HMSHLSPlayer/hooks.ts b/packages/react-native-hms/src/components/HMSHLSPlayer/hooks.ts index bfc6baebb..c1f167cea 100644 --- a/packages/react-native-hms/src/components/HMSHLSPlayer/hooks.ts +++ b/packages/react-native-hms/src/components/HMSHLSPlayer/hooks.ts @@ -1,4 +1,5 @@ import { useEffect } from 'react'; +import { Platform } from 'react-native'; import type { DependencyList } from 'react'; import { shallow } from 'zustand/shallow'; @@ -39,10 +40,18 @@ export const useHMSHLSPlayerStat = < return useHMSHLSPlayerStatsStore((state) => state.stats[stat]); }; -// // The distance of current playback position from the live edge of HLS stream -// export const useIsHLSStreamLive = (liveOffsetMillis: number = 1000) => { -// return useHMSHLSPlayerStatsStore((state) => state.stats.distanceFromLive < liveOffsetMillis); -// } +export const useHMSHLSPlayerSubtitles = () => { + return useHMSHLSPlayerStatsStore((state) => state.subtitles); +}; + +// The distance of current playback position from the live edge of HLS stream +export const useIsHLSStreamLive = ( + liveOffsetMillis: number = Platform.select({ default: 10000, ios: 5000 }) +) => { + return useHMSHLSPlayerStatsStore( + (state) => state.stats.distanceFromLive < liveOffsetMillis + ); +}; // get latest state (without component rerender) @@ -105,3 +114,6 @@ export const setHMSHLSPlayerStats = export const setHMSHLSPlayerStatsError = useHMSHLSPlayerStatsStore.getState().setError; + +export const setHMSHLSPlayerSubtitles = + useHMSHLSPlayerStatsStore.getState().setSubtitles; diff --git a/packages/react-native-hms/src/components/HMSHLSPlayer/index.ts b/packages/react-native-hms/src/components/HMSHLSPlayer/index.ts index 40f412568..a9a13c0d6 100644 --- a/packages/react-native-hms/src/components/HMSHLSPlayer/index.ts +++ b/packages/react-native-hms/src/components/HMSHLSPlayer/index.ts @@ -7,4 +7,6 @@ export { useHMSHLSPlayerStat, useHMSHLSPlayerStatsError, useHMSHLSPlayerResolution, + useHMSHLSPlayerSubtitles, + useIsHLSStreamLive, } from './hooks'; diff --git a/packages/react-native-hms/src/index.ts b/packages/react-native-hms/src/index.ts index e22676d5d..6242ba40c 100644 --- a/packages/react-native-hms/src/index.ts +++ b/packages/react-native-hms/src/index.ts @@ -83,6 +83,7 @@ export * from './classes/HMSCameraControl'; export * from './classes/HMSIOSAudioMode'; export * from './classes/HMSRecordingState'; export * from './classes/HMSStreamingState'; +export * from './classes/HMSHLSPlaylistType'; export type { HMSSessionStore, JsonArray, diff --git a/packages/react-native-hms/src/stores/hls-player-playback-slice.ts b/packages/react-native-hms/src/stores/hls-player-playback-slice.ts index 1fcfe753c..2f59c5dd7 100644 --- a/packages/react-native-hms/src/stores/hls-player-playback-slice.ts +++ b/packages/react-native-hms/src/stores/hls-player-playback-slice.ts @@ -25,4 +25,12 @@ export const createHMSHLSPlayerPlaybackSlice: StateCreator< resolution: undefined, setResolution: (resolution) => set({ resolution }), + + resetPlaybackSlice: () => + set({ + cue: undefined, + playbackState: HMSHLSPlayerPlaybackState.UNKNOWN, + error: undefined, + resolution: undefined, + }), }); diff --git a/packages/react-native-hms/src/stores/hls-player-stats-store.ts b/packages/react-native-hms/src/stores/hls-player-stats-store.ts index 4dd7917a4..d3427183f 100644 --- a/packages/react-native-hms/src/stores/hls-player-stats-store.ts +++ b/packages/react-native-hms/src/stores/hls-player-stats-store.ts @@ -6,32 +6,42 @@ import type { HMSHLSPlayerStatsStore, } from './types'; -export const useHMSHLSPlayerStatsStore = create()( - subscribeWithSelector((set) => ({ - // Handle Stats - stats: { - // bandwidth - bandWidthEstimate: 0, - totalBytesLoaded: 0, +const INITIAL_STATS = { + // bandwidth + bandWidthEstimate: 0, + totalBytesLoaded: 0, - // bufferedDuration - bufferedDuration: 0, + // bufferedDuration + bufferedDuration: 0, - // distanceFromLive - distanceFromLive: 0, + // distanceFromLive + distanceFromLive: 0, - // frameInfo - droppedFrameCount: 0, + // frameInfo + droppedFrameCount: 0, - // videoInfo - averageBitrate: 0, - videoHeight: 0, - videoWidth: 0, - }, + // videoInfo + averageBitrate: 0, + videoHeight: 0, + videoWidth: 0, +}; + +export const useHMSHLSPlayerStatsStore = create()( + subscribeWithSelector((set) => ({ + // Handle Stats + stats: INITIAL_STATS, changeStats: (stats: HMSHLSPlayerStats) => set({ stats }), // Handle Stats Error error: undefined, setError: (error: HMSHLSPlayerStatsError) => set({ error }), + + // Handle Closed Caption + subtitles: null, + setSubtitles: (subtitles: string | null) => set({ subtitles }), + + // Reset State + reset: () => + set({ stats: INITIAL_STATS, error: undefined, subtitles: null }), })) ); diff --git a/packages/react-native-hms/src/stores/types.ts b/packages/react-native-hms/src/stores/types.ts index 28c156eaa..b9db3de48 100644 --- a/packages/react-native-hms/src/stores/types.ts +++ b/packages/react-native-hms/src/stores/types.ts @@ -11,7 +11,8 @@ import type { } from '../types'; export type HMSStore = HMSHLSPlayerPlaybackSlice & HMSViewsSlice; -export type HMSHLSPlayerStatsStore = HMSHLSPlayerStatsSlice; +export type HMSHLSPlayerStatsStore = HMSHLSPlayerStatsSlice & + HLSPlayerClosedCaptionsSlice; export type HMSInteractivityStore = HMSPollsSlice; //#region HMSViews Slice @@ -57,6 +58,7 @@ export interface HMSHLSPlayerPlaybackSlice { setPlaybackState(playbackState: HMSHLSPlayerPlaybackState): void; setResolution(resolution: HMSHLSPlayerResolution): void; setPlaybackError(error: HMSHLSPlayerPlaybackError): void; + resetPlaybackSlice(): void; } //#endregion HLS Player Playback Slice @@ -73,6 +75,12 @@ export interface HMSHLSPlayerStatsSlice { error: HMSHLSPlayerStatsError | undefined; changeStats(stats: HMSHLSPlayerStats): void; setError(error: HMSHLSPlayerStatsError): void; + reset(): void; +} + +export interface HLSPlayerClosedCaptionsSlice { + subtitles: string | null; + setSubtitles(subtitles: string | null): void; } //#endregion HLS Player Stats Slice diff --git a/packages/react-native-hms/src/types.ts b/packages/react-native-hms/src/types.ts index dedf46b88..e3bc96e2f 100644 --- a/packages/react-native-hms/src/types.ts +++ b/packages/react-native-hms/src/types.ts @@ -125,6 +125,21 @@ export type HMSHLSPlayerStatsEvent = | HMSHLSPlayerStatsErrorEvent | HMSHLSPlayerStatsUpdateEvent; +export type HMSHLSPlayerCuesEvent = HMSHLSPlayerEvent< + 'ON_CLOSED_CAPTION_UPDATE', + string | null +>; + +export type RequestedDataEvent = { + requestId: number; + data: any; +}; + +export type HLSPlayerDurationDetails = { + streamDuration?: number; + rollingWindowTime?: number; +}; + // #endregion HMS HLSPlayer Stats Events // #region Utility types diff --git a/packages/react-native-room-kit/example/ExampleAppChangelog.txt b/packages/react-native-room-kit/example/ExampleAppChangelog.txt index 931739e80..77bf7e5e8 100644 --- a/packages/react-native-room-kit/example/ExampleAppChangelog.txt +++ b/packages/react-native-room-kit/example/ExampleAppChangelog.txt @@ -1,15 +1,18 @@ Board: https://100ms.atlassian.net/jira/software/projects/RN/boards/33 -- HLS: Remove webrtc header and footer + Bottom toolbar from HLS screen -https://100ms.atlassian.net/browse/RN-266 +- Captions in HLS Player +https://100ms.atlassian.net/browse/RN-267 -- HLS: Main Player UI with Chat below -https://100ms.atlassian.net/browse/RN-264 +- Header + Description from Layout API in Description Pane +https://100ms.atlassian.net/browse/RN-273 -- HLS: Description Pane -https://100ms.atlassian.net/browse/RN-265 +- Chat Messages starting from the Top +https://100ms.atlassian.net/browse/RN-275 -Room Kit: 1.1.6 -React Native SDK: 1.10.3 +- New Chat Messages design for HLS Player +https://100ms.atlassian.net/browse/RN-276 + +Room Kit: 1.1.7 +React Native SDK: 1.10.4 Android SDK: 2.9.53 iOS SDK: 1.8.0 diff --git a/packages/react-native-room-kit/example/android/app/build.gradle b/packages/react-native-room-kit/example/android/app/build.gradle index b50c96abb..b66165b76 100644 --- a/packages/react-native-room-kit/example/android/app/build.gradle +++ b/packages/react-native-room-kit/example/android/app/build.gradle @@ -136,8 +136,8 @@ android { applicationId "live.hms.rn" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 463 - versionName "2.4.13" + versionCode 470 + versionName "2.4.20" missingDimensionStrategy 'react-native-camera', 'general' } diff --git a/packages/react-native-room-kit/example/ios/Podfile.lock b/packages/react-native-room-kit/example/ios/Podfile.lock index d8c5a60c8..cfc28ff88 100644 --- a/packages/react-native-room-kit/example/ios/Podfile.lock +++ b/packages/react-native-room-kit/example/ios/Podfile.lock @@ -80,10 +80,10 @@ PODS: - HMSHLSPlayerSDK (0.0.2): - HMSAnalyticsSDK (= 0.0.2) - HMSNoiseCancellationModels (1.0.0) - - HMSSDK (1.8.0): + - HMSSDK (1.9.0): - HMSAnalyticsSDK (= 0.0.2) - - HMSWebRTC (= 1.0.5118) - - HMSWebRTC (1.0.5118) + - HMSWebRTC (= 1.0.6168) + - HMSWebRTC (1.0.6168) - libevent (2.1.12) - lottie-ios (3.4.4) - lottie-react-native (5.1.6): @@ -319,11 +319,11 @@ PODS: - React-Core - react-native-camera/RN (4.2.1): - React-Core - - react-native-hms (1.10.3): + - react-native-hms (1.10.4): - HMSBroadcastExtensionSDK (= 0.0.9) - HMSHLSPlayerSDK (= 0.0.2) - HMSNoiseCancellationModels (= 1.0.0) - - HMSSDK (= 1.8.0) + - HMSSDK (= 1.9.0) - React-Core - react-native-lottie-splash-screen (1.1.1): - React @@ -671,8 +671,8 @@ SPEC CHECKSUMS: HMSBroadcastExtensionSDK: d80fe325f6c928bd8e5176290b5a4b7ae15d6fbb HMSHLSPlayerSDK: 6a54ad4d12f3dc2270d1ecd24019d71282a4f6a3 HMSNoiseCancellationModels: a3bda1405a16015632f4bcabd46ce48f35103b02 - HMSSDK: c893d1381a47ed02760ef6d06625b9aa5251f998 - HMSWebRTC: 4487c7200f1e9358412c1d8cd974edd2766467dc + HMSSDK: 96bdafc1c610aabfecd1155ad7e3c1bc45b3a6cb + HMSWebRTC: a302f0d6c94f7bee94f3265adb7bb1c6569e7ee5 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 lottie-ios: 8f97d3271e155c2d688875c29cd3c74908aef5f8 lottie-react-native: 8f9d4be452e23f6e5ca0fdc11669dc99ab52be81 @@ -694,7 +694,7 @@ SPEC CHECKSUMS: React-logger: a1f028f6d8639a3f364ef80419e5e862e1115250 react-native-blur: 172abeaa2de2d3ba4dc586fa23488d01c533818f react-native-camera: 3eae183c1d111103963f3dd913b65d01aef8110f - react-native-hms: 3fff3a052ce7e4670de28e8e5d14c19907352f9b + react-native-hms: 1acd9c4961304f0508551898aee37dd6d5f877b8 react-native-lottie-splash-screen: 015423265bac5f46016dff2e31c97b9590808856 react-native-safe-area-context: 61c8c484a3a9e7d1fda19f7b1794b35bbfd2262a react-native-simple-toast: bf002828cf816775a6809f7a9ec3907509bce11f diff --git a/packages/react-native-room-kit/example/ios/RNExample.xcodeproj/project.pbxproj b/packages/react-native-room-kit/example/ios/RNExample.xcodeproj/project.pbxproj index 514a31088..b901af484 100644 --- a/packages/react-native-room-kit/example/ios/RNExample.xcodeproj/project.pbxproj +++ b/packages/react-native-room-kit/example/ios/RNExample.xcodeproj/project.pbxproj @@ -502,7 +502,7 @@ CODE_SIGN_ENTITLEMENTS = RNExample/RNExample.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 463; + CURRENT_PROJECT_VERSION = 470; DEVELOPMENT_TEAM = 5N85PP82A9; ENABLE_BITCODE = NO; INFOPLIST_FILE = RNExample/Info.plist; @@ -540,7 +540,7 @@ CODE_SIGN_ENTITLEMENTS = RNExample/RNExample.entitlements; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 463; + CURRENT_PROJECT_VERSION = 470; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 5N85PP82A9; INFOPLIST_FILE = RNExample/Info.plist; @@ -703,7 +703,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = RNExampleBroadcastUpload/RNExampleBroadcastUpload.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 463; + CURRENT_PROJECT_VERSION = 470; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 5N85PP82A9; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -745,7 +745,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 463; + CURRENT_PROJECT_VERSION = 470; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 5N85PP82A9; diff --git a/packages/react-native-room-kit/example/ios/RNExample/Info.plist b/packages/react-native-room-kit/example/ios/RNExample/Info.plist index cb6c902ea..425dc25bd 100644 --- a/packages/react-native-room-kit/example/ios/RNExample/Info.plist +++ b/packages/react-native-room-kit/example/ios/RNExample/Info.plist @@ -21,11 +21,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.4.13 + 2.4.20 CFBundleSignature ???? CFBundleVersion - 463 + 470 ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/packages/react-native-room-kit/example/package-lock.json b/packages/react-native-room-kit/example/package-lock.json index b60484338..db985b4e7 100644 --- a/packages/react-native-room-kit/example/package-lock.json +++ b/packages/react-native-room-kit/example/package-lock.json @@ -1,12 +1,12 @@ { "name": "RNExample", - "version": "1.1.6", + "version": "1.1.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "RNExample", - "version": "1.1.6", + "version": "1.1.7", "dependencies": { "@react-native-async-storage/async-storage": "1.17.11", "@react-native-community/blur": "^4.3.2", @@ -85,25 +85,25 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz", - "integrity": "sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.3.tgz", - "integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.1", + "@babel/generator": "^7.24.4", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.1", - "@babel/parser": "^7.24.1", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", "@babel/template": "^7.24.0", "@babel/traverse": "^7.24.1", "@babel/types": "^7.24.0", @@ -122,9 +122,9 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", - "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", "dependencies": { "@babel/types": "^7.24.0", "@jridgewell/gen-mapping": "^0.3.5", @@ -173,9 +173,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.1.tgz", - "integrity": "sha512-1yJa9dX9g//V6fDebXoEfEsxkZHk3Hcbm+zLhyu6qVgYFLvmTALTeV+jNU9e5RnYtioBrGEOdoI2joMSNQ/+aA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz", + "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", @@ -418,9 +418,9 @@ } }, "node_modules/@babel/helpers": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz", - "integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", "dependencies": { "@babel/template": "^7.24.0", "@babel/traverse": "^7.24.1", @@ -445,9 +445,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", - "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -455,6 +455,22 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz", + "integrity": "sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA==", + "peer": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.24.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", @@ -968,9 +984,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.1.tgz", - "integrity": "sha512-h71T2QQvDgM2SmT29UYU6ozjMlAt7s7CSs5Hvy8f8cf/GM/Z4a2zMfN+fjVGaieeCrXR3EdQl6C4gQG+OgmbKw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz", + "integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -998,12 +1014,12 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.1.tgz", - "integrity": "sha512-FUHlKCn6J3ERiu8Dv+4eoz7w8+kFLSyeVG4vDAikwADGjUCoHw/JHokyGtr8OR4UjpwPVivyF+h8Q5iv/JmrtA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz", + "integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==", "peer": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-create-class-features-plugin": "^7.24.4", "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, @@ -1701,12 +1717,12 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.1.tgz", - "integrity": "sha512-liYSESjX2fZ7JyBFkYG78nfvHlMKE6IpNdTVnxmlYUR+j5ZLsitFbaAE+eJSK2zPPkNWNw4mXL51rQ8WrvdK0w==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.4.tgz", + "integrity": "sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-create-class-features-plugin": "^7.24.4", "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-typescript": "^7.24.1" }, @@ -1780,15 +1796,16 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.3.tgz", - "integrity": "sha512-fSk430k5c2ff8536JcPvPWK4tZDwehWLGlBp0wrsBUjZVdeQV6lePbwKWZaZfK2vnh/1kQX1PzAJWsnBmVgGJA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.4.tgz", + "integrity": "sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A==", "peer": true, "dependencies": { - "@babel/compat-data": "^7.24.1", + "@babel/compat-data": "^7.24.4", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.4", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1", @@ -1815,9 +1832,9 @@ "@babel/plugin-transform-async-generator-functions": "^7.24.3", "@babel/plugin-transform-async-to-generator": "^7.24.1", "@babel/plugin-transform-block-scoped-functions": "^7.24.1", - "@babel/plugin-transform-block-scoping": "^7.24.1", + "@babel/plugin-transform-block-scoping": "^7.24.4", "@babel/plugin-transform-class-properties": "^7.24.1", - "@babel/plugin-transform-class-static-block": "^7.24.1", + "@babel/plugin-transform-class-static-block": "^7.24.4", "@babel/plugin-transform-classes": "^7.24.1", "@babel/plugin-transform-computed-properties": "^7.24.1", "@babel/plugin-transform-destructuring": "^7.24.1", @@ -1965,9 +1982,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", - "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", + "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -4309,9 +4326,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.12.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.2.tgz", - "integrity": "sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==", + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "dependencies": { "undici-types": "~5.26.4" } @@ -5465,19 +5482,16 @@ } }, "node_modules/babel-plugin-module-resolver": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.0.tgz", - "integrity": "sha512-g0u+/ChLSJ5+PzYwLwP8Rp8Rcfowz58TJNCe+L/ui4rpzE/mg//JVX0EWBUYoxaextqnwuGHzfGp2hh0PPV25Q==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.2.tgz", + "integrity": "sha512-9KtaCazHee2xc0ibfqsDeamwDps6FZNo5S0Q81dUqEuFzVwPhcT4J5jOqIVvgCA3Q/wO9hKYxN/Ds3tIsp5ygg==", "dev": true, "dependencies": { - "find-babel-config": "^2.0.0", - "glob": "^8.0.3", + "find-babel-config": "^2.1.1", + "glob": "^9.3.3", "pkg-up": "^3.1.0", "reselect": "^4.1.7", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">= 16" + "resolve": "^1.22.8" } }, "node_modules/babel-plugin-polyfill-corejs2": { @@ -5840,9 +5854,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001603", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001603.tgz", - "integrity": "sha512-iL2iSS0eDILMb9n5yKQoTBim9jMZ0Yrk8g0N9K7UzYyWnfIKzXBZD5ngpM37ZcL/cv0Mli8XtVMRYMQAfFpi5Q==", + "version": "1.0.30001612", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", + "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", "funding": [ { "type": "opencollective", @@ -6176,9 +6190,9 @@ } }, "node_modules/core-js-compat": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", - "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz", + "integrity": "sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==", "dependencies": { "browserslist": "^4.23.0" }, @@ -6555,9 +6569,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.722", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.722.tgz", - "integrity": "sha512-5nLE0TWFFpZ80Crhtp4pIp8LXCztjYX41yUcV6b+bKR2PqzjskTMOOlBi1VjBHlvHwS+4gar7kNKOrsbsewEZQ==" + "version": "1.4.745", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.745.tgz", + "integrity": "sha512-tRbzkaRI5gbUn5DEvF0dV4TQbMZ5CLkWeTAXmpC9IrYT+GE+x76i9p+o3RJ5l9XmdQlI1pPhVtE9uNcJJ0G0EA==" }, "node_modules/emittery": { "version": "0.7.2", @@ -6606,9 +6620,9 @@ } }, "node_modules/envinfo": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz", - "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.12.0.tgz", + "integrity": "sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==", "bin": { "envinfo": "dist/cli.js" }, @@ -7726,16 +7740,13 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/find-babel-config": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-2.0.0.tgz", - "integrity": "sha512-dOKT7jvF3hGzlW60Gc3ONox/0rRZ/tz7WCil0bqA1In/3I8f1BctpXahRnEKDySZqci7u+dqq93sZST9fOJpFw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-2.1.1.tgz", + "integrity": "sha512-5Ji+EAysHGe1OipH7GN4qDjok5Z1uw5KAwDCbicU/4wyTZY7CqOCzcWbG7J5ad9mazq67k89fXlbc1MuIfl9uA==", "dev": true, "dependencies": { - "json5": "^2.1.1", + "json5": "^2.2.3", "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" } }, "node_modules/find-cache-dir": { @@ -8080,19 +8091,18 @@ } }, "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -8120,15 +8130,18 @@ } }, "node_modules/glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/globals": { @@ -10822,9 +10835,9 @@ } }, "node_modules/joi": { - "version": "17.12.2", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.2.tgz", - "integrity": "sha512-RonXAIzCiHLc8ss3Ibuz45u28GOsWE1UpfDXLbN/9NKbL4tCJf8TWYVKsoYuuh+sAUt7fsSNpA+r2+TBA6Wjmw==", + "version": "17.12.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.3.tgz", + "integrity": "sha512-2RRziagf555owrm9IRVtdKynOBeITiDpuZqIpgwqXShPncPKNiRQoiGsl/T8SQdq+8ugRzH2LqY67irr2y/d+g==", "dependencies": { "@hapi/hoek": "^9.3.0", "@hapi/topo": "^5.1.0", @@ -12004,6 +12017,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -12277,9 +12299,9 @@ "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==" }, "node_modules/nwsapi": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", - "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz", + "integrity": "sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==", "dev": true }, "node_modules/ob1": { @@ -12724,6 +12746,40 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-scurry": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -13230,9 +13286,9 @@ "integrity": "sha512-mubYMN6+1HXa8z3EJKBvNBkl4UoVM4McjESeB2PgvRMSngmJtC5yUMRdhbbrIAn5Liu3hFGao/14s5hQIgtkRQ==" }, "node_modules/react-native-lottie-splash-screen/node_modules/lottie-react-native": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-6.7.0.tgz", - "integrity": "sha512-doiF/36LaKkzo0XkgUIK8egxALNY6jGjCI4szpRuwop15LTW3DFtIA2L3pusNdaH7oM797aSH5UylIJw2k+Hgw==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-6.7.2.tgz", + "integrity": "sha512-MZVx6N1EeO/EaSx8T44mJ0aHc5Mqee+xIfWwszni0oz8U2wlHdaWGjES44dHxaxgAp/0dRaFt3PkpZ6egTzcBg==", "peerDependencies": { "@dotlottie/react-player": "^1.6.1", "@lottiefiles/react-lottie-player": "^3.5.3", diff --git a/packages/react-native-room-kit/example/package.json b/packages/react-native-room-kit/example/package.json index 816b70d3b..c866fca67 100644 --- a/packages/react-native-room-kit/example/package.json +++ b/packages/react-native-room-kit/example/package.json @@ -1,6 +1,6 @@ { "name": "RNExample", - "version": "1.1.6", + "version": "1.1.7", "private": true, "scripts": { "android": "react-native run-android", diff --git a/packages/react-native-room-kit/package-lock.json b/packages/react-native-room-kit/package-lock.json index d6482697b..bce0d9b78 100644 --- a/packages/react-native-room-kit/package-lock.json +++ b/packages/react-native-room-kit/package-lock.json @@ -1,12 +1,12 @@ { "name": "@100mslive/react-native-room-kit", - "version": "1.1.6", + "version": "1.1.7", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@100mslive/react-native-room-kit", - "version": "1.1.6", + "version": "1.1.7", "license": "MIT", "dependencies": { "@100mslive/types-prebuilt": "^0.12.8", @@ -40,7 +40,7 @@ "node": ">= 16.0.0" }, "peerDependencies": { - "@100mslive/react-native-hms": "1.10.3", + "@100mslive/react-native-hms": "1.10.4", "@react-native-community/blur": "^4.3.2", "@react-native-masked-view/masked-view": "^0.2.9", "@shopify/flash-list": "^1.4.3", @@ -56,9 +56,9 @@ } }, "node_modules/@100mslive/react-native-hms": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/@100mslive/react-native-hms/-/react-native-hms-1.10.3.tgz", - "integrity": "sha512-pz/kVm6qf5YORLsv8wFwiZxzpH14ewe4tzd5NoNRI8APpjYMKda2EYb5IFIukMRwh1LWb83W3C7cL828lrnxuA==", + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@100mslive/react-native-hms/-/react-native-hms-1.10.4.tgz", + "integrity": "sha512-nCf+0Y+1cSSUBIACviSkjdwBgBElmoD+4QpGv0wHE9PNsdeO8QHWj9ceFlVcPvjQVCTM/5S3STpeM540DWGuZw==", "peer": true, "dependencies": { "zustand": "^4.3.8" @@ -107,25 +107,25 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz", - "integrity": "sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.3.tgz", - "integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.1", + "@babel/generator": "^7.24.4", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.1", - "@babel/parser": "^7.24.1", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", "@babel/template": "^7.24.0", "@babel/traverse": "^7.24.1", "@babel/types": "^7.24.0", @@ -162,9 +162,9 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", - "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", "dependencies": { "@babel/types": "^7.24.0", "@jridgewell/gen-mapping": "^0.3.5", @@ -213,9 +213,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.1.tgz", - "integrity": "sha512-1yJa9dX9g//V6fDebXoEfEsxkZHk3Hcbm+zLhyu6qVgYFLvmTALTeV+jNU9e5RnYtioBrGEOdoI2joMSNQ/+aA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz", + "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", @@ -474,9 +474,9 @@ } }, "node_modules/@babel/helpers": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz", - "integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", "dependencies": { "@babel/template": "^7.24.0", "@babel/traverse": "^7.24.1", @@ -501,9 +501,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", - "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -511,6 +511,21 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz", + "integrity": "sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.24.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", @@ -1013,9 +1028,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.1.tgz", - "integrity": "sha512-h71T2QQvDgM2SmT29UYU6ozjMlAt7s7CSs5Hvy8f8cf/GM/Z4a2zMfN+fjVGaieeCrXR3EdQl6C4gQG+OgmbKw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz", + "integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -1042,11 +1057,11 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.1.tgz", - "integrity": "sha512-FUHlKCn6J3ERiu8Dv+4eoz7w8+kFLSyeVG4vDAikwADGjUCoHw/JHokyGtr8OR4UjpwPVivyF+h8Q5iv/JmrtA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz", + "integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-create-class-features-plugin": "^7.24.4", "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, @@ -1755,12 +1770,12 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.1.tgz", - "integrity": "sha512-liYSESjX2fZ7JyBFkYG78nfvHlMKE6IpNdTVnxmlYUR+j5ZLsitFbaAE+eJSK2zPPkNWNw4mXL51rQ8WrvdK0w==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.4.tgz", + "integrity": "sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-create-class-features-plugin": "^7.24.4", "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-typescript": "^7.24.1" }, @@ -1831,14 +1846,15 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.3.tgz", - "integrity": "sha512-fSk430k5c2ff8536JcPvPWK4tZDwehWLGlBp0wrsBUjZVdeQV6lePbwKWZaZfK2vnh/1kQX1PzAJWsnBmVgGJA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.4.tgz", + "integrity": "sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A==", "dependencies": { - "@babel/compat-data": "^7.24.1", + "@babel/compat-data": "^7.24.4", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.4", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1", @@ -1865,9 +1881,9 @@ "@babel/plugin-transform-async-generator-functions": "^7.24.3", "@babel/plugin-transform-async-to-generator": "^7.24.1", "@babel/plugin-transform-block-scoped-functions": "^7.24.1", - "@babel/plugin-transform-block-scoping": "^7.24.1", + "@babel/plugin-transform-block-scoping": "^7.24.4", "@babel/plugin-transform-class-properties": "^7.24.1", - "@babel/plugin-transform-class-static-block": "^7.24.1", + "@babel/plugin-transform-class-static-block": "^7.24.4", "@babel/plugin-transform-classes": "^7.24.1", "@babel/plugin-transform-computed-properties": "^7.24.1", "@babel/plugin-transform-destructuring": "^7.24.1", @@ -2051,9 +2067,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", - "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", + "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2769,9 +2785,9 @@ } }, "node_modules/@evilmartians/lefthook": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@evilmartians/lefthook/-/lefthook-1.6.7.tgz", - "integrity": "sha512-nRCNWUl4xxkIwzChkARezEGuIcm6l2aywDPR3C4f8bGTzDJhVtEPcByqrOqPJ9emS7MnYz9WKI/NFdIsph/apw==", + "version": "1.6.10", + "resolved": "https://registry.npmjs.org/@evilmartians/lefthook/-/lefthook-1.6.10.tgz", + "integrity": "sha512-4qhV1QAuROrxUAifXzhNZAcHOiPPLJnBl+XwSHRB/PdkoFbEa5bh4d5drO5pLjknKy7XXAXOTK/49Ew3ipuo7w==", "cpu": [ "x64", "arm64", @@ -2829,9 +2845,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, "node_modules/@hutson/parse-repository-url": { @@ -7162,9 +7178,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001603", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001603.tgz", - "integrity": "sha512-iL2iSS0eDILMb9n5yKQoTBim9jMZ0Yrk8g0N9K7UzYyWnfIKzXBZD5ngpM37ZcL/cv0Mli8XtVMRYMQAfFpi5Q==", + "version": "1.0.30001612", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", + "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", "funding": [ { "type": "opencollective", @@ -8009,9 +8025,9 @@ } }, "node_modules/core-js-compat": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", - "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz", + "integrity": "sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==", "dependencies": { "browserslist": "^4.23.0" }, @@ -8910,9 +8926,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.722", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.722.tgz", - "integrity": "sha512-5nLE0TWFFpZ80Crhtp4pIp8LXCztjYX41yUcV6b+bKR2PqzjskTMOOlBi1VjBHlvHwS+4gar7kNKOrsbsewEZQ==" + "version": "1.4.745", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.745.tgz", + "integrity": "sha512-tRbzkaRI5gbUn5DEvF0dV4TQbMZ5CLkWeTAXmpC9IrYT+GE+x76i9p+o3RJ5l9XmdQlI1pPhVtE9uNcJJ0G0EA==" }, "node_modules/emittery": { "version": "0.10.2", @@ -8948,9 +8964,9 @@ } }, "node_modules/envinfo": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz", - "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.12.0.tgz", + "integrity": "sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==", "bin": { "envinfo": "dist/cli.js" }, @@ -14288,9 +14304,9 @@ } }, "node_modules/joi": { - "version": "17.12.2", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.2.tgz", - "integrity": "sha512-RonXAIzCiHLc8ss3Ibuz45u28GOsWE1UpfDXLbN/9NKbL4tCJf8TWYVKsoYuuh+sAUt7fsSNpA+r2+TBA6Wjmw==", + "version": "17.12.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.3.tgz", + "integrity": "sha512-2RRziagf555owrm9IRVtdKynOBeITiDpuZqIpgwqXShPncPKNiRQoiGsl/T8SQdq+8ugRzH2LqY67irr2y/d+g==", "dependencies": { "@hapi/hoek": "^9.3.0", "@hapi/topo": "^5.1.0", @@ -20452,9 +20468,9 @@ } }, "node_modules/socks": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", - "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dev": true, "dependencies": { "ip-address": "^9.0.5", @@ -21414,9 +21430,9 @@ } }, "node_modules/typescript": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", - "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -22358,9 +22374,9 @@ }, "dependencies": { "@100mslive/react-native-hms": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/@100mslive/react-native-hms/-/react-native-hms-1.10.3.tgz", - "integrity": "sha512-pz/kVm6qf5YORLsv8wFwiZxzpH14ewe4tzd5NoNRI8APpjYMKda2EYb5IFIukMRwh1LWb83W3C7cL828lrnxuA==", + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@100mslive/react-native-hms/-/react-native-hms-1.10.4.tgz", + "integrity": "sha512-nCf+0Y+1cSSUBIACviSkjdwBgBElmoD+4QpGv0wHE9PNsdeO8QHWj9ceFlVcPvjQVCTM/5S3STpeM540DWGuZw==", "peer": true, "requires": { "zustand": "^4.3.8" @@ -22396,22 +22412,22 @@ } }, "@babel/compat-data": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz", - "integrity": "sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==" + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==" }, "@babel/core": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.3.tgz", - "integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", "requires": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.1", + "@babel/generator": "^7.24.4", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.1", - "@babel/parser": "^7.24.1", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", "@babel/template": "^7.24.0", "@babel/traverse": "^7.24.1", "@babel/types": "^7.24.0", @@ -22434,9 +22450,9 @@ } }, "@babel/generator": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", - "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", "requires": { "@babel/types": "^7.24.0", "@jridgewell/gen-mapping": "^0.3.5", @@ -22473,9 +22489,9 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.1.tgz", - "integrity": "sha512-1yJa9dX9g//V6fDebXoEfEsxkZHk3Hcbm+zLhyu6qVgYFLvmTALTeV+jNU9e5RnYtioBrGEOdoI2joMSNQ/+aA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz", + "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==", "requires": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", @@ -22655,9 +22671,9 @@ } }, "@babel/helpers": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz", - "integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", "requires": { "@babel/template": "^7.24.0", "@babel/traverse": "^7.24.1", @@ -22676,9 +22692,18 @@ } }, "@babel/parser": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", - "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==" + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==" + }, + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz", + "integrity": "sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" + } }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.24.1", @@ -22995,9 +23020,9 @@ } }, "@babel/plugin-transform-block-scoping": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.1.tgz", - "integrity": "sha512-h71T2QQvDgM2SmT29UYU6ozjMlAt7s7CSs5Hvy8f8cf/GM/Z4a2zMfN+fjVGaieeCrXR3EdQl6C4gQG+OgmbKw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz", + "integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==", "requires": { "@babel/helper-plugin-utils": "^7.24.0" } @@ -23012,11 +23037,11 @@ } }, "@babel/plugin-transform-class-static-block": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.1.tgz", - "integrity": "sha512-FUHlKCn6J3ERiu8Dv+4eoz7w8+kFLSyeVG4vDAikwADGjUCoHw/JHokyGtr8OR4UjpwPVivyF+h8Q5iv/JmrtA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz", + "integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-create-class-features-plugin": "^7.24.4", "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-class-static-block": "^7.14.5" } @@ -23443,12 +23468,12 @@ } }, "@babel/plugin-transform-typescript": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.1.tgz", - "integrity": "sha512-liYSESjX2fZ7JyBFkYG78nfvHlMKE6IpNdTVnxmlYUR+j5ZLsitFbaAE+eJSK2zPPkNWNw4mXL51rQ8WrvdK0w==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.4.tgz", + "integrity": "sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g==", "requires": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-create-class-features-plugin": "^7.24.4", "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-typescript": "^7.24.1" } @@ -23489,14 +23514,15 @@ } }, "@babel/preset-env": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.3.tgz", - "integrity": "sha512-fSk430k5c2ff8536JcPvPWK4tZDwehWLGlBp0wrsBUjZVdeQV6lePbwKWZaZfK2vnh/1kQX1PzAJWsnBmVgGJA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.4.tgz", + "integrity": "sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A==", "requires": { - "@babel/compat-data": "^7.24.1", + "@babel/compat-data": "^7.24.4", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.4", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1", @@ -23523,9 +23549,9 @@ "@babel/plugin-transform-async-generator-functions": "^7.24.3", "@babel/plugin-transform-async-to-generator": "^7.24.1", "@babel/plugin-transform-block-scoped-functions": "^7.24.1", - "@babel/plugin-transform-block-scoping": "^7.24.1", + "@babel/plugin-transform-block-scoping": "^7.24.4", "@babel/plugin-transform-class-properties": "^7.24.1", - "@babel/plugin-transform-class-static-block": "^7.24.1", + "@babel/plugin-transform-class-static-block": "^7.24.4", "@babel/plugin-transform-classes": "^7.24.1", "@babel/plugin-transform-computed-properties": "^7.24.1", "@babel/plugin-transform-destructuring": "^7.24.1", @@ -23669,9 +23695,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "@babel/runtime": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", - "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", + "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", "requires": { "regenerator-runtime": "^0.14.0" } @@ -24211,9 +24237,9 @@ "dev": true }, "@evilmartians/lefthook": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@evilmartians/lefthook/-/lefthook-1.6.7.tgz", - "integrity": "sha512-nRCNWUl4xxkIwzChkARezEGuIcm6l2aywDPR3C4f8bGTzDJhVtEPcByqrOqPJ9emS7MnYz9WKI/NFdIsph/apw==", + "version": "1.6.10", + "resolved": "https://registry.npmjs.org/@evilmartians/lefthook/-/lefthook-1.6.10.tgz", + "integrity": "sha512-4qhV1QAuROrxUAifXzhNZAcHOiPPLJnBl+XwSHRB/PdkoFbEa5bh4d5drO5pLjknKy7XXAXOTK/49Ew3ipuo7w==", "dev": true }, "@hapi/hoek": { @@ -24247,9 +24273,9 @@ "dev": true }, "@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, "@hutson/parse-repository-url": { @@ -27557,9 +27583,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001603", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001603.tgz", - "integrity": "sha512-iL2iSS0eDILMb9n5yKQoTBim9jMZ0Yrk8g0N9K7UzYyWnfIKzXBZD5ngpM37ZcL/cv0Mli8XtVMRYMQAfFpi5Q==" + "version": "1.0.30001612", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", + "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==" }, "capture-exit": { "version": "2.0.0", @@ -28205,9 +28231,9 @@ "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==" }, "core-js-compat": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", - "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz", + "integrity": "sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==", "requires": { "browserslist": "^4.23.0" } @@ -28807,9 +28833,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "electron-to-chromium": { - "version": "1.4.722", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.722.tgz", - "integrity": "sha512-5nLE0TWFFpZ80Crhtp4pIp8LXCztjYX41yUcV6b+bKR2PqzjskTMOOlBi1VjBHlvHwS+4gar7kNKOrsbsewEZQ==" + "version": "1.4.745", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.745.tgz", + "integrity": "sha512-tRbzkaRI5gbUn5DEvF0dV4TQbMZ5CLkWeTAXmpC9IrYT+GE+x76i9p+o3RJ5l9XmdQlI1pPhVtE9uNcJJ0G0EA==" }, "emittery": { "version": "0.10.2", @@ -28836,9 +28862,9 @@ } }, "envinfo": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz", - "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==" + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.12.0.tgz", + "integrity": "sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==" }, "error-ex": { "version": "1.3.2", @@ -32713,9 +32739,9 @@ "integrity": "sha512-3Zi16h6L5tXDRQJTb221cnRoVG9/9OvreLdLU2/ZjRv/GILL+2Cemt0IKvkowwkDpvouAU1DQPOJ7qaiHeIdrw==" }, "joi": { - "version": "17.12.2", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.2.tgz", - "integrity": "sha512-RonXAIzCiHLc8ss3Ibuz45u28GOsWE1UpfDXLbN/9NKbL4tCJf8TWYVKsoYuuh+sAUt7fsSNpA+r2+TBA6Wjmw==", + "version": "17.12.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.3.tgz", + "integrity": "sha512-2RRziagf555owrm9IRVtdKynOBeITiDpuZqIpgwqXShPncPKNiRQoiGsl/T8SQdq+8ugRzH2LqY67irr2y/d+g==", "requires": { "@hapi/hoek": "^9.3.0", "@hapi/topo": "^5.1.0", @@ -37398,9 +37424,9 @@ } }, "socks": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", - "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dev": true, "requires": { "ip-address": "^9.0.5", @@ -38114,9 +38140,9 @@ } }, "typescript": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", - "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true }, "uglify-es": { diff --git a/packages/react-native-room-kit/package.json b/packages/react-native-room-kit/package.json index c308e7de0..553f40a42 100644 --- a/packages/react-native-room-kit/package.json +++ b/packages/react-native-room-kit/package.json @@ -1,6 +1,6 @@ { "name": "@100mslive/react-native-room-kit", - "version": "1.1.6", + "version": "1.1.7", "description": "100ms Room Kit provides simple & easy to use UI components to build Live Streaming & Video Conferencing experiences in your apps.", "main": "lib/commonjs/index", "module": "lib/module/index", @@ -140,7 +140,7 @@ "typescript": "^5.0.2" }, "peerDependencies": { - "@100mslive/react-native-hms": "1.10.3", + "@100mslive/react-native-hms": "1.10.4", "@react-native-community/blur": "^4.3.2", "@react-native-masked-view/masked-view": "^0.2.9", "@shopify/flash-list": "^1.4.3", diff --git a/packages/react-native-room-kit/src/Icons/Pause/assets/pause-med.png b/packages/react-native-room-kit/src/Icons/Pause/assets/pause-med.png new file mode 100644 index 000000000..12d5d4ff6 Binary files /dev/null and b/packages/react-native-room-kit/src/Icons/Pause/assets/pause-med.png differ diff --git a/packages/react-native-room-kit/src/Icons/Pause/assets/pause-med@2x.png b/packages/react-native-room-kit/src/Icons/Pause/assets/pause-med@2x.png new file mode 100644 index 000000000..175e757c3 Binary files /dev/null and b/packages/react-native-room-kit/src/Icons/Pause/assets/pause-med@2x.png differ diff --git a/packages/react-native-room-kit/src/Icons/Pause/assets/pause-med@3x.png b/packages/react-native-room-kit/src/Icons/Pause/assets/pause-med@3x.png new file mode 100644 index 000000000..8d5a15f89 Binary files /dev/null and b/packages/react-native-room-kit/src/Icons/Pause/assets/pause-med@3x.png differ diff --git a/packages/react-native-room-kit/src/Icons/Pause/index.tsx b/packages/react-native-room-kit/src/Icons/Pause/index.tsx new file mode 100644 index 000000000..b1a4601f8 --- /dev/null +++ b/packages/react-native-room-kit/src/Icons/Pause/index.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { Image, StyleSheet } from 'react-native'; +import type { ImageProps } from 'react-native'; + +interface PauseIconProps extends Omit { + size?: 'med'; +} + +export const PauseIcon: React.FC = ({ + style, + size = 'med', + ...restProps +}) => { + if (size !== 'med') return null; + + return ( + + ); +}; + +const styles = StyleSheet.create({ + icon: { + width: 24, + height: 24, + alignItems: 'center', + justifyContent: 'center', + }, + medIcon: { + width: 48, + height: 48, + }, +}); diff --git a/packages/react-native-room-kit/src/Icons/Play/assets/play-med.png b/packages/react-native-room-kit/src/Icons/Play/assets/play-med.png new file mode 100644 index 000000000..2d9251c0c Binary files /dev/null and b/packages/react-native-room-kit/src/Icons/Play/assets/play-med.png differ diff --git a/packages/react-native-room-kit/src/Icons/Play/assets/play-med@2x.png b/packages/react-native-room-kit/src/Icons/Play/assets/play-med@2x.png new file mode 100644 index 000000000..35960de69 Binary files /dev/null and b/packages/react-native-room-kit/src/Icons/Play/assets/play-med@2x.png differ diff --git a/packages/react-native-room-kit/src/Icons/Play/assets/play-med@3x.png b/packages/react-native-room-kit/src/Icons/Play/assets/play-med@3x.png new file mode 100644 index 000000000..874575802 Binary files /dev/null and b/packages/react-native-room-kit/src/Icons/Play/assets/play-med@3x.png differ diff --git a/packages/react-native-room-kit/src/Icons/Play/index.tsx b/packages/react-native-room-kit/src/Icons/Play/index.tsx new file mode 100644 index 000000000..a03fb64fa --- /dev/null +++ b/packages/react-native-room-kit/src/Icons/Play/index.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { Image, StyleSheet } from 'react-native'; +import type { ImageProps } from 'react-native'; + +interface PlayIconProps extends Omit { + size?: 'med'; +} + +export const PlayIcon: React.FC = ({ + style, + size = 'med', + ...restProps +}) => { + if (size !== 'med') return null; + + return ( + + ); +}; + +const styles = StyleSheet.create({ + icon: { + width: 24, + height: 24, + alignItems: 'center', + justifyContent: 'center', + }, + medIcon: { + width: 48, + height: 48, + }, +}); diff --git a/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-backward-arrow.png b/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-backward-arrow.png new file mode 100644 index 000000000..9c3b659df Binary files /dev/null and b/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-backward-arrow.png differ diff --git a/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-backward-arrow@2x.png b/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-backward-arrow@2x.png new file mode 100644 index 000000000..74a186703 Binary files /dev/null and b/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-backward-arrow@2x.png differ diff --git a/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-backward-arrow@3x.png b/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-backward-arrow@3x.png new file mode 100644 index 000000000..4480b2fbf Binary files /dev/null and b/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-backward-arrow@3x.png differ diff --git a/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-forward-arrow.png b/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-forward-arrow.png new file mode 100644 index 000000000..9bb3a0881 Binary files /dev/null and b/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-forward-arrow.png differ diff --git a/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-forward-arrow@2x.png b/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-forward-arrow@2x.png new file mode 100644 index 000000000..1393d872f Binary files /dev/null and b/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-forward-arrow@2x.png differ diff --git a/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-forward-arrow@3x.png b/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-forward-arrow@3x.png new file mode 100644 index 000000000..0b5efa63a Binary files /dev/null and b/packages/react-native-room-kit/src/Icons/SeekArrow/assets/seek-forward-arrow@3x.png differ diff --git a/packages/react-native-room-kit/src/Icons/SeekArrow/index.tsx b/packages/react-native-room-kit/src/Icons/SeekArrow/index.tsx new file mode 100644 index 000000000..2734832b1 --- /dev/null +++ b/packages/react-native-room-kit/src/Icons/SeekArrow/index.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { Image, StyleSheet } from 'react-native'; +import type { ImageProps } from 'react-native'; + +import { useHMSRoomStyle } from '../../hooks-util'; + +interface SeekArrowIconProps extends Omit { + type: 'forward' | 'backward'; +} + +export const SeekArrowIcon: React.FC = ({ + style, + type, + ...restProps +}) => { + const iconStyles = useHMSRoomStyle((theme) => ({ + tintColor: theme.palette.on_surface_high, + })); + + return ( + + ); +}; + +const styles = StyleSheet.create({ + icon: { + width: 32, + height: 32, + alignItems: 'center', + justifyContent: 'center', + }, +}); diff --git a/packages/react-native-room-kit/src/Icons/index.ts b/packages/react-native-room-kit/src/Icons/index.ts index 72ea3b372..b76a940ee 100644 --- a/packages/react-native-room-kit/src/Icons/index.ts +++ b/packages/react-native-room-kit/src/Icons/index.ts @@ -48,3 +48,6 @@ export * from './Add'; export * from './PollVote'; export * from './CheckBox'; export * from './CC'; +export * from './Pause'; +export * from './Play'; +export * from './SeekArrow'; diff --git a/packages/react-native-room-kit/src/components/CustomHLSPlayerControls.tsx b/packages/react-native-room-kit/src/components/CustomHLSPlayerControls.tsx deleted file mode 100644 index 4a2d62687..000000000 --- a/packages/react-native-room-kit/src/components/CustomHLSPlayerControls.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import React from 'react'; -import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'; - -import { COLORS } from '../utils/theme'; - -export type ControlType = - | 'play' - | 'stop' - | 'pause' - | 'resume' - | 'seekForward' - | 'seekBackward' - | 'seekToLive' - | 'setVolume'; - -export interface CustomControlsProps { - handleControlPress(action: ControlType, data?: any): void; -} - -export const CustomControls: React.FC = ({ - handleControlPress, -}) => { - return ( - - - handleControlPress('play')} - > - Play - - handleControlPress('stop')} - > - Stop - - handleControlPress('pause')} - > - Pause - - handleControlPress('resume')} - > - Resume - - - - handleControlPress('seekForward', 5)} - > - Forward 5 sec - - handleControlPress('seekBackward', 5)} - > - Backward 5 sec - - - - handleControlPress('seekToLive')} - > - Go to Live - - handleControlPress('setVolume', 50)} - > - Low Volume to `50` - - - - ); -}; - -const styles = StyleSheet.create({ - wrapper: { flexDirection: 'row', justifyContent: 'space-evenly' }, - spacedWrapper: { - flexDirection: 'row', - justifyContent: 'space-evenly', - marginVertical: 8, - }, - button: { padding: 12 }, - text: { color: COLORS.PRIMARY.LIGHT }, -}); diff --git a/packages/react-native-room-kit/src/components/HLSChatMessages.tsx b/packages/react-native-room-kit/src/components/HLSChatMessages.tsx index bff137950..8547ae8f3 100644 --- a/packages/react-native-room-kit/src/components/HLSChatMessages.tsx +++ b/packages/react-native-room-kit/src/components/HLSChatMessages.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; -import { Platform, StyleSheet, View } from 'react-native'; +import { FlatList, Platform, StyleSheet, View } from 'react-native'; import { useSelector } from 'react-redux'; -import { FlashList } from '@shopify/flash-list'; import type { HMSMessage } from '@100mslive/react-native-hms'; import type { RootState } from '../redux'; @@ -32,11 +31,10 @@ export const HLSChatMessages = () => { {messages.length > 0 ? ( - void; +} + +export const _HLSCloseMeetingControl: React.FC = ({ + onPress, +}) => { + const { handleModalVisibleType } = useModalType(); + + const handleCloseBtnPress = () => { + onPress?.(); + handleModalVisibleType(ModalTypes.LEAVE_ROOM); + }; + + return ( + + + + + + ); +}; + +export const HLSCloseMeetingControl = React.memo(_HLSCloseMeetingControl); + +const styles = StyleSheet.create({ + icon: { + padding: 4, + alignSelf: 'flex-start', + }, +}); diff --git a/packages/react-native-room-kit/src/components/HLSClosedCaptionControl.tsx b/packages/react-native-room-kit/src/components/HLSClosedCaptionControl.tsx new file mode 100644 index 000000000..0a31cd5d0 --- /dev/null +++ b/packages/react-native-room-kit/src/components/HLSClosedCaptionControl.tsx @@ -0,0 +1,140 @@ +import React, { useRef, useState } from 'react'; +import { StyleSheet, TouchableOpacity } from 'react-native'; +import { useSelector } from 'react-redux'; +import { + useHMSHLSPlayerPlaybackState, + HMSHLSPlayerPlaybackState, +} from '@100mslive/react-native-hms'; +import type { HMSHLSPlayer } from '@100mslive/react-native-hms'; +import { GestureDetector, Gesture } from 'react-native-gesture-handler'; + +import { CCIcon } from '../Icons'; +import type { RootState } from '../redux'; +import { useIsHLSStreamingOn } from '../hooks-sdk'; + +interface HLSClosedCaptionControlProps { + playerRef: React.RefObject>; + onPress?: () => void; +} + +export const _HLSClosedCaptionControl: React.FC< + HLSClosedCaptionControlProps +> = ({ playerRef, onPress }) => { + const isHLSStreamingOn = useIsHLSStreamingOn(); + const isStreamUrlPresent = useSelector( + (state: RootState) => + !!state.hmsStates.room?.hlsStreamingState.variants?.[0]?.hlsStreamUrl + ); + + let startedPlayingFirstTimeRef = useRef(false); + let prevPlaybackStateRef = useRef(HMSHLSPlayerPlaybackState.UNKNOWN); + const playbackState = useHMSHLSPlayerPlaybackState(); + + if ( + prevPlaybackStateRef.current === HMSHLSPlayerPlaybackState.UNKNOWN && + playbackState === HMSHLSPlayerPlaybackState.PLAYING + ) { + prevPlaybackStateRef.current = playbackState; + startedPlayingFirstTimeRef.current = true; + } + + const [isCCSupported, setIsCCSupported] = useState(false); + const [isCCEnabled, setIsCCEnabled] = useState(true); + + const handleCCBtnPress = () => { + if (!isCCSupported || !playerRef.current) { + return; + } + onPress?.(); + if (isCCEnabled) { + playerRef.current.disableClosedCaption(); + setIsCCEnabled(false); + } else { + playerRef.current.enableClosedCaption(); + setIsCCEnabled(true); + } + }; + + React.useEffect(() => { + if ( + isHLSStreamingOn && + isStreamUrlPresent && + startedPlayingFirstTimeRef.current && + playerRef.current + ) { + let mounted = true; + + playerRef.current + .isClosedCaptionSupported() + .then((supported) => { + if (mounted) { + setIsCCSupported(supported); + } + }) + .catch(() => {}); + playerRef.current + .isClosedCaptionEnabled() + .then((enabled) => { + if (mounted) { + setIsCCEnabled(enabled); + } + }) + .catch(() => {}); + + return () => { + mounted = false; + }; + } + }, [ + isHLSStreamingOn, + isStreamUrlPresent, + startedPlayingFirstTimeRef.current, + ]); + + if (!isCCSupported) { + return null; + } + + return ( + + + + + + ); +}; + +export const HLSClosedCaptionControl = React.memo(_HLSClosedCaptionControl); + +const styles = StyleSheet.create({ + detectorContainer: { + position: 'absolute', + width: '100%', + height: '100%', + zIndex: 5, + }, + container: { + flex: 1, + justifyContent: 'space-between', + }, + controlsRow: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + marginHorizontal: 8, + }, + normalRow: { + flexDirection: 'row', + alignItems: 'center', + }, + icon: { + padding: 4, + alignSelf: 'flex-start', + }, + gap: { + marginLeft: 16, + }, +}); diff --git a/packages/react-native-room-kit/src/components/HLSDistanceFromLive.tsx b/packages/react-native-room-kit/src/components/HLSDistanceFromLive.tsx new file mode 100644 index 000000000..9ae14e4bf --- /dev/null +++ b/packages/react-native-room-kit/src/components/HLSDistanceFromLive.tsx @@ -0,0 +1,69 @@ +import React from 'react'; +import { Platform, StyleSheet, Text } from 'react-native'; +import { + HMSHLSPlaylistType, + useHMSHLSPlayerStat, + useIsHLSStreamLive, +} from '@100mslive/react-native-hms'; +import { useSelector } from 'react-redux'; + +import { useHMSRoomStyle } from '../hooks-util'; +import { useIsHLSStreamingOn } from '../hooks-sdk'; +import type { RootState } from '../redux'; + +interface HLSDistanceFromLiveProps {} + +export const _HLSDistanceFromLive: React.FC = () => { + const isHLSStreamingOn = useIsHLSStreamingOn(); + const isDVRStream = useSelector( + (state: RootState) => + state.hmsStates.room?.hlsStreamingState.variants?.[0]?.playlistType === + HMSHLSPlaylistType.DVR + ); + const isStreamLive = useIsHLSStreamLive(); + + if (!isHLSStreamingOn || !isDVRStream || isStreamLive) return null; + + return ; +}; + +export const HLSDistanceFromLiveText = React.memo(() => { + const distanceFromLiveEdge = useHMSHLSPlayerStat('distanceFromLive'); + + const textStyle = useHMSRoomStyle((_, typography) => ({ + fontFamily: `${typography.font_family}-Regular`, + color: '#ffffff', + })); + + const hhmmss = msToHMS( + distanceFromLiveEdge - Platform.select({ default: 10000, ios: 1000 }) + ); + + return -{hhmmss}; +}); + +export const HLSDistanceFromLive = React.memo(_HLSDistanceFromLive); + +const styles = StyleSheet.create({ + text: { + fontSize: 16, + lineHeight: 24, + letterSpacing: 0.5, + marginLeft: 8, + }, +}); + +function msToHMS(ms: number) { + const seconds = Math.floor((ms / 1000) % 60); + const minutes = Math.floor((ms / 1000 / 60) % 60); + const hours = Math.floor((ms / 1000 / 3600) % 24); + + const humanized = [ + minutes > 0 ? minutes.toString().padStart(2, '0') : '0', + seconds.toString().padStart(2, '0'), + ]; + + if (hours > 0) humanized.unshift(hours.toString().padStart(2, '0')); + + return humanized.join(':'); +} diff --git a/packages/react-native-room-kit/src/components/HLSFullScreenControl.tsx b/packages/react-native-room-kit/src/components/HLSFullScreenControl.tsx new file mode 100644 index 000000000..7844a52b0 --- /dev/null +++ b/packages/react-native-room-kit/src/components/HLSFullScreenControl.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { StyleSheet, TouchableOpacity } from 'react-native'; +import { useDispatch, useSelector } from 'react-redux'; +import { GestureDetector, Gesture } from 'react-native-gesture-handler'; + +import { MaximizeIcon, MinimizeIcon } from '../Icons'; +import type { RootState } from '../redux'; +import { setHlsFullScreen } from '../redux/actions'; + +interface HLSFullScreenControlProps { + onPress?: () => void; +} + +export const _HLSFullScreenControl: React.FC = ({ + onPress, +}) => { + const dispatch = useDispatch(); + const hlsFullScreen = useSelector( + (state: RootState) => state.app.hlsFullScreen + ); + const toggleFullScreen = () => { + onPress?.(); + dispatch(setHlsFullScreen(!hlsFullScreen)); + }; + + return ( + + + {hlsFullScreen ? ( + + ) : ( + + )} + + + ); +}; + +export const HLSFullScreenControl = React.memo(_HLSFullScreenControl); + +const styles = StyleSheet.create({ + icon: { + padding: 4, + alignSelf: 'flex-start', + }, +}); diff --git a/packages/react-native-room-kit/src/components/HLSGoLiveControl.tsx b/packages/react-native-room-kit/src/components/HLSGoLiveControl.tsx new file mode 100644 index 000000000..e1ee64f29 --- /dev/null +++ b/packages/react-native-room-kit/src/components/HLSGoLiveControl.tsx @@ -0,0 +1,104 @@ +import React from 'react'; +import { View, StyleSheet, TouchableOpacity, Text } from 'react-native'; +import { useSelector } from 'react-redux'; +import { + HMSHLSPlaylistType, + useIsHLSStreamLive, +} from '@100mslive/react-native-hms'; +import type { HMSHLSPlayer } from '@100mslive/react-native-hms'; +import { GestureDetector, Gesture } from 'react-native-gesture-handler'; + +import { useHMSRoomStyleSheet } from '../hooks-util'; +import { useIsHLSStreamingOn } from '../hooks-sdk'; +import type { RootState } from '../redux'; + +interface HLSGoLiveControlProps { + playerRef: React.RefObject>; + onPress?: () => void; +} + +export const _HLSGoLiveControl: React.FC = ({ + playerRef, + onPress, +}) => { + const isHLSStreamingOn = useIsHLSStreamingOn(); + const isDVRStream = useSelector( + (state: RootState) => + state.hmsStates.room?.hlsStreamingState.variants?.[0]?.playlistType === + HMSHLSPlaylistType.DVR + ); + const isStreamLive = useIsHLSStreamLive(); + + const handleGoLivePress = () => { + onPress?.(); + playerRef.current?.seekToLivePosition(); + }; + + const hmsRoomStyles = useHMSRoomStyleSheet( + (theme, typography) => ({ + semiBoldSurfaceHigh: { + fontFamily: `${typography.font_family}-SemiBold`, + color: theme.palette.on_surface_high, + }, + semiBoldSurfaceMedium: { + fontFamily: `${typography.font_family}-SemiBold`, + color: theme.palette.on_surface_medium, + }, + liveIndicatorDot: { + backgroundColor: theme.palette.alert_error_default, + }, + notLiveIndicatorDot: { + backgroundColor: theme.palette.on_surface_low, + }, + }), + [] + ); + + if (!isHLSStreamingOn || !isDVRStream) return null; + + return ( + + + + + {isStreamLive ? 'LIVE' : 'GO LIVE'} + + + + ); +}; + +export const HLSGoLiveControl = React.memo(_HLSGoLiveControl); + +const styles = StyleSheet.create({ + liveButton: { + padding: 4, + alignItems: 'center', + flexDirection: 'row', + }, + liveIndicatorDot: { + width: 8, + height: 8, + borderRadius: 4, + marginRight: 8, + }, + liveText: { + fontSize: 16, + lineHeight: 24, + letterSpacing: 0.5, + }, +}); diff --git a/packages/react-native-room-kit/src/components/HLSPlayPauseControl.tsx b/packages/react-native-room-kit/src/components/HLSPlayPauseControl.tsx new file mode 100644 index 000000000..f0d5e9daf --- /dev/null +++ b/packages/react-native-room-kit/src/components/HLSPlayPauseControl.tsx @@ -0,0 +1,69 @@ +import { HMSHLSPlaylistType } from '@100mslive/react-native-hms'; +import type { HMSHLSPlayer } from '@100mslive/react-native-hms'; +import * as React from 'react'; +import { StyleSheet, TouchableOpacity, View } from 'react-native'; +import { useSelector } from 'react-redux'; +import { GestureDetector, Gesture } from 'react-native-gesture-handler'; + +import { useIsHLSStreamingOn } from '../hooks-sdk'; +import type { RootState } from '../redux'; +import { PauseIcon, PlayIcon } from '../Icons'; +import { useHLSStreamResumePause } from '../hooks-util'; + +export interface HLSPlayPauseControlProps { + playerRef: React.RefObject>; + onPress?: () => void; +} + +const _HLSPlayPauseControl: React.FC = ({ + playerRef, + onPress, +}) => { + const isHLSStreamingOn = useIsHLSStreamingOn(); + const isDVRStream = useSelector((state: RootState) => { + return ( + state.hmsStates.room?.hlsStreamingState.variants?.[0]?.playlistType === + HMSHLSPlaylistType.DVR + ); + }); + + const { isPaused, pauseStream, resumeStream } = + useHLSStreamResumePause(playerRef); + + const togglePlayPause = () => { + onPress?.(); + if (isPaused) { + resumeStream(); + } else { + pauseStream(); + } + }; + + if (!isHLSStreamingOn || !isDVRStream) return null; + + return ( + + + + {isPaused ? : } + + + + ); +}; + +export const HLSPlayPauseControl = React.memo(_HLSPlayPauseControl); + +const styles = StyleSheet.create({ + container: { + width: 64, + height: 64, + borderRadius: 32, + alignItems: 'center', + justifyContent: 'center', + backgroundColor: 'rgba(0, 0, 0, 0.6)', + }, +}); diff --git a/packages/react-native-room-kit/src/components/HLSPlayer.tsx b/packages/react-native-room-kit/src/components/HLSPlayer.tsx index 2e168f1c7..3bd6eee63 100644 --- a/packages/react-native-room-kit/src/components/HLSPlayer.tsx +++ b/packages/react-native-room-kit/src/components/HLSPlayer.tsx @@ -1,6 +1,5 @@ -import React, { useRef } from 'react'; -import type { ComponentRef } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import React from 'react'; +import { useSelector } from 'react-redux'; import { View, Text, @@ -12,96 +11,53 @@ import { HMSHLSPlayer, HMSHLSPlayerPlaybackState, useHMSHLSPlayerPlaybackState, + useHMSHLSPlayerSubtitles, } from '@100mslive/react-native-hms'; import type { RootState } from '../redux'; -import { changeShowHLSStats } from '../redux/actions'; -import { HLSPlayerStatsView } from './HLSPlayerStatsView'; +// import { changeShowHLSStats } from '../redux/actions'; +// import { HLSPlayerStatsView } from './HLSPlayerStatsView'; import { HLSPlayerEmoticons } from './HLSPlayerEmoticons'; -import { CustomControls } from './CustomHLSPlayerControls'; import { COLORS, hexToRgbA } from '../utils/theme'; import { HMSHLSNotStarted } from './HMSHLSNotStarted'; import { CrossCircleIcon } from '../Icons'; import { useHLSPlayerConstraints, + useHLSViewsConstraints, useHMSRoomColorPalette, useHMSRoomStyleSheet, } from '../hooks-util'; import { useIsHLSStreamingOn } from '../hooks-sdk'; +import { HMSPinchGesture } from './PeerVideoTile/HMSPinchGesture'; -export const _HLSPlayer: React.FC = () => { - const dispatch = useDispatch(); +export interface HLSPlayerProps {} + +export const _HLSPlayer = React.forwardRef< + React.ElementRef, + HLSPlayerProps +>((_props, hlsPlayerRef) => { + // const dispatch = useDispatch(); const isHLSStreaming = useIsHLSStreamingOn(); const isStreamUrlPresent = useSelector( (state: RootState) => !!state.hmsStates.room?.hlsStreamingState.variants?.[0]?.hlsStreamUrl ); - const hmsHlsPlayerRef = useRef>(null); - const showHLSStats = useSelector( - (state: RootState) => state.app.joinConfig.showHLSStats - ); - const showCustomHLSPlayerControls = useSelector( - (state: RootState) => state.app.joinConfig.showCustomHLSPlayerControls - ); + // const showHLSStats = useSelector( + // (state: RootState) => state.app.joinConfig.showHLSStats + // ); + // const showCustomHLSPlayerControls = useSelector( + // (state: RootState) => state.app.joinConfig.showCustomHLSPlayerControls + // ); const enableHLSPlayerControls = useSelector( (state: RootState) => state.app.joinConfig.enableHLSPlayerControls ); - const handleClosePress = () => { - dispatch(changeShowHLSStats(false)); - }; - - const hlsPlayerActions = < - T extends - | 'play' - | 'stop' - | 'pause' - | 'resume' - | 'seekForward' - | 'seekBackward' - | 'seekToLive' - | 'setVolume', - >( - action: T, - ...args: any[] - ) => { - switch (action) { - case 'play': { - hmsHlsPlayerRef.current?.play(args[0]); - break; - } - case 'stop': { - hmsHlsPlayerRef.current?.stop(); - break; - } - case 'pause': { - hmsHlsPlayerRef.current?.pause(); - break; - } - case 'resume': { - hmsHlsPlayerRef.current?.resume(); - break; - } - case 'seekForward': { - hmsHlsPlayerRef.current?.seekForward(args[0]); - break; - } - case 'seekBackward': { - hmsHlsPlayerRef.current?.seekBackward(args[0]); - break; - } - case 'seekToLive': { - hmsHlsPlayerRef.current?.seekToLivePosition(); - break; - } - case 'setVolume': { - hmsHlsPlayerRef.current?.setVolume(args[0]); - break; - } - } - }; + // const handleClosePress = () => { + // dispatch(changeShowHLSStats(false)); + // }; const hlsPlayerConstraints = useHLSPlayerConstraints(); + const { playerWrapperConstraints } = useHLSViewsConstraints(); const [playerKey, setPlayerKey] = React.useState(1); const prevReconnectingRef = React.useRef(null); @@ -111,6 +67,8 @@ export const _HLSPlayer: React.FC = () => { const hlsPlayerPlaybackState = useHMSHLSPlayerPlaybackState(); + const subtitles = useHMSHLSPlayerSubtitles(); + const isPlaybackFailed = hlsPlayerPlaybackState === HMSHLSPlayerPlaybackState.FAILED; @@ -147,6 +105,10 @@ export const _HLSPlayer: React.FC = () => { color: theme.palette.alert_warning, fontFamily: `${typography.font_family}-SemiBold`, }, + semiboldWhite: { + fontFamily: `${typography.font_family}-SemiBold`, + color: '#ffffff', + }, })); const { primary_bright: PrimaryBrightColor } = useHMSRoomColorPalette(); @@ -164,26 +126,50 @@ export const _HLSPlayer: React.FC = () => { return ( <> - + + + + + + + + + + + {subtitles} + + + + - {showHLSStats ? ( + {/* {showHLSStats ? ( - ) : null} - - {showCustomHLSPlayerControls ? ( - - ) : null} + ) : null} */} {isPlayerBuffering ? ( { ) : null} ); -}; +}); export const HLSPlayer = React.memo(_HLSPlayer); const styles = StyleSheet.create({ - hlsView: { + container: { flex: 1, + alignItems: 'center', + justifyContent: 'center', }, - hlsPlayerContainer: { - // flex: 1, + playerAndCaptionWrapper: { position: 'relative', + alignItems: 'center', + justifyContent: 'center', + }, + playerContainer: { + flex: undefined, + alignItems: 'flex-start', + justifyContent: 'flex-start', }, textContainer: { flex: 1, @@ -236,6 +230,22 @@ const styles = StyleSheet.create({ letterSpacing: 0.25, textAlign: 'center', }, + closedCaptionsContainer: { + position: 'absolute', + bottom: 4, + paddingHorizontal: 8, + paddingVertical: 4, + alignItems: 'center', + justifyContent: 'center', + }, + closedCaptions: { + fontSize: 14, + lineHeight: 16, + textAlign: 'center', + textShadowColor: 'rgba(0, 0, 0, 0.8)', + textShadowRadius: 3, + textShadowOffset: { width: 1, height: 1 }, + }, playbackFailedContainer: { flex: 1, width: '100%', diff --git a/packages/react-native-room-kit/src/components/HLSPlayerContainer.tsx b/packages/react-native-room-kit/src/components/HLSPlayerContainer.tsx index 41a78f4e3..8b9593032 100644 --- a/packages/react-native-room-kit/src/components/HLSPlayerContainer.tsx +++ b/packages/react-native-room-kit/src/components/HLSPlayerContainer.tsx @@ -1,29 +1,96 @@ import React from 'react'; import { View, StyleSheet } from 'react-native'; +import type { HMSHLSPlayer } from '@100mslive/react-native-hms'; +import { Gesture, GestureDetector } from 'react-native-gesture-handler'; +import { + Easing, + cancelAnimation, + useSharedValue, + withDelay, + withTiming, +} from 'react-native-reanimated'; import { useHLSViewsConstraints } from '../hooks-util'; import { HLSPlayer } from './HLSPlayer'; import { HLSPlayerControls } from './HLSPlayerControls'; export const _HLSPlayerContainer: React.FC = () => { - // const hlsPlayerRef = useRef(null); + const hlsPlayerRef = + React.useRef>(null); const { playerWrapperConstraints } = useHLSViewsConstraints(); + const animatedValue = useSharedValue(1); + + const cancelCurrentControlAnimation = React.useCallback(() => { + 'worklet'; + cancelAnimation(animatedValue); + }, []); + + const hideControlsAfterDelay = React.useCallback((duration = 500) => { + 'worklet'; + animatedValue.value = withDelay( + 5000, + withTiming(0, { duration, easing: Easing.ease }) + ); + }, []); + + const resetHideControlAnimation = React.useCallback(() => { + cancelCurrentControlAnimation(); + hideControlsAfterDelay(); + }, [cancelCurrentControlAnimation, hideControlsAfterDelay]); + + const hideControls = React.useCallback((duration = 500) => { + 'worklet'; + animatedValue.value = withTiming(0, { duration, easing: Easing.ease }); + }, []); + + React.useEffect(() => { + resetHideControlAnimation(); + }, [resetHideControlAnimation]); + + const tapGesture = React.useMemo(() => { + return Gesture.Tap().onStart(() => { + cancelCurrentControlAnimation(); + if (animatedValue.value < 1) { + animatedValue.value = withTiming( + 1, + { duration: 200, easing: Easing.ease }, + (finished) => { + if (finished) { + hideControlsAfterDelay(); + } + } + ); + } else { + hideControls(200); + } + }); + }, [cancelCurrentControlAnimation, hideControls, hideControlsAfterDelay]); + return ( - - + + + - - + + + ); }; diff --git a/packages/react-native-room-kit/src/components/HLSPlayerControls.tsx b/packages/react-native-room-kit/src/components/HLSPlayerControls.tsx index a4ed27a98..8a34ffd24 100644 --- a/packages/react-native-room-kit/src/components/HLSPlayerControls.tsx +++ b/packages/react-native-room-kit/src/components/HLSPlayerControls.tsx @@ -1,85 +1,164 @@ import React from 'react'; -import { View, StyleSheet, TouchableOpacity } from 'react-native'; -import { useDispatch, useSelector } from 'react-redux'; +import { View, StyleSheet } from 'react-native'; +import type { ViewProps, ViewStyle } from 'react-native'; +import { useSelector } from 'react-redux'; +import Animated, { + useAnimatedProps, + useAnimatedStyle, +} from 'react-native-reanimated'; +import type { SharedValue } from 'react-native-reanimated'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; +import type { HMSHLSPlayer } from '@100mslive/react-native-hms'; -import { - // CCIcon, - CloseIcon, - MaximizeIcon, - MinimizeIcon, -} from '../Icons'; -import { ModalTypes } from '../utils/types'; -import { useModalType } from '../hooks-util'; import type { RootState } from '../redux'; -import { setHlsFullScreen } from '../redux/actions'; +import { HLSGoLiveControl } from './HLSGoLiveControl'; +import { HLSSeekbar } from './HLSSeekbar'; +import { useIsLandscapeOrientation } from '../utils/dimension'; +import { HLSCloseMeetingControl } from './HLSCloseMeetingControl'; +import { HLSClosedCaptionControl } from './HLSClosedCaptionControl'; +import { HLSFullScreenControl } from './HLSFullScreenControl'; +import { HLSDistanceFromLive } from './HLSDistanceFromLive'; +import { HLSPlayPauseControl } from './HLSPlayPauseControl'; +import { HLSSeekbackwardControl } from './HLSSeekbackwardControl'; +import { HLSSeekforwardControl } from './HLSSeekforwardControl'; -export const _HLSPlayerControls: React.FC = () => { - // const isHLSStreaming = useIsHLSStreamingOn(); - // const isStreamUrlPresent = useSelector( - // (state: RootState) => - // !!state.hmsStates.room?.hlsStreamingState.variants?.[0]?.hlsStreamUrl - // ); - const dispatch = useDispatch(); +interface HLSPlayerControlsProps { + playerRef: React.RefObject>; + cancelCurrentControlAnimation: () => void; + hideControlsAfterDelay: () => void; + resetHideControlAnimation: () => void; + animatedValue: SharedValue; +} + +export const _HLSPlayerControls: React.FC = ({ + playerRef, + cancelCurrentControlAnimation, + hideControlsAfterDelay, + animatedValue, + resetHideControlAnimation, +}) => { + const { bottom: bottomSafeInset } = useSafeAreaInsets(); + const isLandscapeOrientation = useIsLandscapeOrientation(); const hlsFullScreen = useSelector( (state: RootState) => state.app.hlsFullScreen ); - const { handleModalVisibleType } = useModalType(); - - const handleCloseBtnPress = () => { - handleModalVisibleType(ModalTypes.LEAVE_ROOM); - }; - // const handleCCBtnPress = () => { - // // - // }; + const hideControlsStyles: ViewStyle = useAnimatedStyle( + () => ({ + opacity: animatedValue.value, + }), + [] + ); - const toggleFullScreen = () => { - dispatch(setHlsFullScreen(!hlsFullScreen)); - }; + const hideControlsProps: ViewProps = useAnimatedProps( + () => ({ + pointerEvents: animatedValue.value < 0.8 ? 'none' : 'auto', + }), + [] + ); return ( - - - - - + + {/* Play/Pause Controls */} + + + + + - {/* - - - - */} - + + + - - + {/* Header Controls */} + + + - - - {hlsFullScreen ? ( - - ) : ( - - )} - + + + - - + + + {/* Footer Controls */} + + + + + + + + + + + + + + + + + ); }; export const HLSPlayerControls = React.memo(_HLSPlayerControls); const styles = StyleSheet.create({ - container: { + floatingContainer: { position: 'absolute', width: '100%', - height: '100%', zIndex: 5, - justifyContent: 'space-between', }, controlsRow: { flexDirection: 'row', diff --git a/packages/react-native-room-kit/src/components/HLSSeekbackwardControl.tsx b/packages/react-native-room-kit/src/components/HLSSeekbackwardControl.tsx new file mode 100644 index 000000000..248759c58 --- /dev/null +++ b/packages/react-native-room-kit/src/components/HLSSeekbackwardControl.tsx @@ -0,0 +1,88 @@ +import { HMSHLSPlaylistType } from '@100mslive/react-native-hms'; +import type { HMSHLSPlayer } from '@100mslive/react-native-hms'; +import * as React from 'react'; +import { useSelector } from 'react-redux'; +import { GestureDetector, Gesture } from 'react-native-gesture-handler'; + +import { useIsHLSStreamingOn } from '../hooks-sdk'; +import type { RootState } from '../redux'; +import { SeekArrowIcon } from '../Icons'; +import Animated, { + Easing, + cancelAnimation, + interpolate, + runOnJS, + useAnimatedStyle, + useSharedValue, + withTiming, +} from 'react-native-reanimated'; + +export interface HLSSeekbackwardControlProps { + playerRef: React.RefObject>; + onPress?: () => void; +} + +const _HLSSeekbackwardControl: React.FC = ({ + playerRef, + onPress, +}) => { + const animatedValue = useSharedValue(0); + const isHLSStreamingOn = useIsHLSStreamingOn(); + const isDVRStream = useSelector((state: RootState) => { + return ( + state.hmsStates.room?.hlsStreamingState.variants?.[0]?.playlistType === + HMSHLSPlaylistType.DVR + ); + }); + + const handdleSeekBackward = () => { + onPress?.(); + playerRef.current?.seekBackward(10); + }; + + const tapGestureHandler = React.useMemo(() => { + return Gesture.Tap().onStart(() => { + cancelAnimation(animatedValue); + animatedValue.value = withTiming( + 1, + { duration: 200, easing: Easing.ease }, + (finished) => { + if (finished) { + animatedValue.value = withTiming(0, { + duration: 100, + easing: Easing.ease, + }); + } + } + ); + runOnJS(handdleSeekBackward)(); + }); + }, []); + + const animatedStyle = useAnimatedStyle( + () => ({ + opacity: interpolate(animatedValue.value, [0, 1], [1, 0.8]), + transform: [ + { + rotateZ: `${interpolate(animatedValue.value, [0, 1], [0, -17])} deg`, + }, + ], + }), + [] + ); + + if (!isHLSStreamingOn || !isDVRStream) return null; + + return ( + + + + + + ); +}; + +export const HLSSeekbackwardControl = React.memo(_HLSSeekbackwardControl); diff --git a/packages/react-native-room-kit/src/components/HLSSeekbar.tsx b/packages/react-native-room-kit/src/components/HLSSeekbar.tsx new file mode 100644 index 000000000..d823e5be3 --- /dev/null +++ b/packages/react-native-room-kit/src/components/HLSSeekbar.tsx @@ -0,0 +1,381 @@ +import React, { useRef } from 'react'; +import { View, StyleSheet } from 'react-native'; +import Animated, { + Easing, + Extrapolation, + interpolate, + runOnJS, + useAnimatedStyle, + useDerivedValue, + useSharedValue, + withTiming, +} from 'react-native-reanimated'; +import { GestureDetector, Gesture } from 'react-native-gesture-handler'; +import { + HMSHLSPlayerPlaybackState, + HMSHLSPlaylistType, + useHMSHLSPlayerPlaybackState, + useHMSHLSPlayerStat, +} from '@100mslive/react-native-hms'; +import type { + HLSPlayerDurationDetails, + HMSHLSPlayer, +} from '@100mslive/react-native-hms'; +import { useSelector } from 'react-redux'; + +import { + useHLSStreamResumePause, + useHLSViewsConstraints, + useHMSRoomStyle, +} from '../hooks-util'; +import { useIsHLSStreamingOn } from '../hooks-sdk'; +import type { RootState } from '../redux'; + +interface HLSSeekbarProps { + playerRef: React.RefObject>; + onStart: () => void; + onEnd: () => void; +} + +export const _HLSSeekbar: React.FC = (props) => { + const isHLSStreamingOn = useIsHLSStreamingOn(); + const isDVRStream = useSelector((state: RootState) => { + return ( + state.hmsStates.room?.hlsStreamingState.variants?.[0]?.playlistType === + HMSHLSPlaylistType.DVR + ); + }); + + if (!isHLSStreamingOn || !isDVRStream) return null; + + return <_Seekbar {...props} />; +}; + +const _Seekbar: React.FC = React.memo( + ({ playerRef, onStart, onEnd }) => { + const { playerWrapperConstraints } = useHLSViewsConstraints(); + const hlsPlayerDurationDetails = useRef( + null + ); + const prevSeekbarPositionValue = useSharedValue(0); + const seekbarPositionValue = useSharedValue(0); + const seekbarHeightValue = useSharedValue(4); + const streamStartedAt = useSelector((state: RootState) => { + return state.hmsStates.room?.hlsStreamingState.variants?.[0]?.startedAt; + }); + const distanceFromLiveEdge = useHMSHLSPlayerStat('distanceFromLive'); + const distanceFromLiveEdgeValue = useDerivedValue( + () => distanceFromLiveEdge, + [distanceFromLiveEdge] + ); + + const seekbarRoomStyle = useHMSRoomStyle((theme) => ({ + backgroundColor: theme.palette.primary_default, + })); + + const { isPaused, pauseStream, resumeStream } = + useHLSStreamResumePause(playerRef); + + const seekToBarPosition = () => { + if (!streamStartedAt) return; + const liveStreamDuration = Date.now() - streamStartedAt.getTime(); + const rollingWindowTime = + hlsPlayerDurationDetails.current?.rollingWindowTime; + const durationOfStream = + rollingWindowTime && liveStreamDuration >= rollingWindowTime + ? rollingWindowTime + : liveStreamDuration; + + // console.log( + // '$$$ rolling window time > ', + // hlsPlayerDurationDetails.current?.rollingWindowTime + // ); + // console.log('$$$ live stream duration > ', liveStreamDuration); + // console.log('$$$ current stream duration > ', durationOfStream); + + const prevPosition = prevSeekbarPositionValue.value; + const currPosition = seekbarPositionValue.value; + const diff = currPosition - prevPosition; + const seekByMillis = (durationOfStream / 100) * Math.abs(diff); + + const seekBySecs = seekByMillis / 1000; + if (diff >= 0) { + playerRef.current?.seekForward(seekBySecs); + } else { + playerRef.current?.seekBackward(seekBySecs); + } + resumeStream(); + }; + + const activeSeekbarStyle = useAnimatedStyle( + () => ({ + width: interpolate( + seekbarPositionValue.value, + [0, 100], + [0, playerWrapperConstraints.width], + { + extrapolateLeft: Extrapolation.CLAMP, + extrapolateRight: Extrapolation.CLAMP, + } + ), + height: seekbarHeightValue.value, + }), + [playerWrapperConstraints.width] + ); + + const activeSeekbarThumbStyle = useAnimatedStyle( + () => ({ + width: seekbarHeightValue.value * 3, + height: seekbarHeightValue.value * 3, + borderRadius: (seekbarHeightValue.value * 3) / 2, + bottom: -seekbarHeightValue.value, + left: -(seekbarHeightValue.value * 3) / 2, + transform: [ + { + translateX: interpolate( + seekbarPositionValue.value, + [0, 100], + [0, playerWrapperConstraints.width], + { + extrapolateLeft: Extrapolation.CLAMP, + extrapolateRight: Extrapolation.CLAMP, + } + ), + }, + ], + }), + [playerWrapperConstraints.width] + ); + + const panGesture = Gesture.Pan() + .maxPointers(1) + .minPointers(1) + .hitSlop({ top: 12, bottom: 12 }) + .onStart((e) => { + 'worklet'; + onStart(); + runOnJS(pauseStream)(); + prevSeekbarPositionValue.value = seekbarPositionValue.value; + seekbarPositionValue.value = interpolate( + e.x, + [0, playerWrapperConstraints.width], + [0, 100], + { + extrapolateLeft: Extrapolation.CLAMP, + extrapolateRight: Extrapolation.CLAMP, + } + ); + seekbarHeightValue.value = withTiming(6, { + duration: 160, + easing: Easing.linear, + }); + }) + .onUpdate((e) => { + 'worklet'; + seekbarPositionValue.value = interpolate( + e.x, + [0, playerWrapperConstraints.width], + [0, 100], + { + extrapolateLeft: Extrapolation.CLAMP, + extrapolateRight: Extrapolation.CLAMP, + } + ); + }) + .onEnd(() => { + 'worklet'; + onEnd(); + seekbarHeightValue.value = withTiming(4, { + duration: 160, + easing: Easing.linear, + }); + runOnJS(seekToBarPosition)(); + }); + + React.useEffect(() => { + if (streamStartedAt && !isPaused) { + const intervalId = setInterval(() => { + const liveStreamDuration = Date.now() - streamStartedAt.getTime(); + + const rollingWindowTime = + hlsPlayerDurationDetails.current?.rollingWindowTime; + + const durationOfStream = + rollingWindowTime && liveStreamDuration >= rollingWindowTime + ? rollingWindowTime + : liveStreamDuration; + + // console.log( + // '$$$ rolling window time > ', + // hlsPlayerDurationDetails.current?.rollingWindowTime + // ); + // console.log('$$$ live stream duration > ', liveStreamDuration); + // console.log('$$$ current stream duration > ', durationOfStream); + + const currentPosition = + durationOfStream - distanceFromLiveEdgeValue.value; + + // console.log('currentPosition > ', currentPosition); + + seekbarPositionValue.value = interpolate( + currentPosition, + [0, durationOfStream], + [0, 100], + { + extrapolateLeft: Extrapolation.CLAMP, + extrapolateRight: Extrapolation.CLAMP, + } + ); + }, 1000); + + return () => { + clearInterval(intervalId); + }; + } + }, [isPaused, streamStartedAt]); + + let startedPlayingFirstTime = false; + let prevPlaybackState = HMSHLSPlayerPlaybackState.UNKNOWN; + const playbackState = useHMSHLSPlayerPlaybackState(); + + if ( + prevPlaybackState === HMSHLSPlayerPlaybackState.UNKNOWN && + playbackState === HMSHLSPlayerPlaybackState.PLAYING + ) { + prevPlaybackState = playbackState; + startedPlayingFirstTime = true; + } + + React.useEffect(() => { + if (startedPlayingFirstTime && playerRef.current) { + let mounted = true; + + playerRef.current + .getPlayerDurationDetails() + .then((data) => { + if (mounted) { + console.log('$$$ getPlayerDurationDetails > ', data); + hlsPlayerDurationDetails.current = data; + if ( + typeof data.rollingWindowTime === 'number' && + data.rollingWindowTime < 300000 + ) { + hlsPlayerDurationDetails.current.rollingWindowTime = 300000; + } + } + }) + .catch(() => {}); + + return () => { + mounted = false; + }; + } + }, [startedPlayingFirstTime]); + + return ( + + + + + + + + + ); + } +); + +export const HLSSeekbar = React.memo(_HLSSeekbar); + +const styles = StyleSheet.create({ + container: { + height: 6, + justifyContent: 'flex-end', + }, + inactiveSeekbar: { + position: 'relative', + backgroundColor: 'rgba(255, 255, 255, 0.25)', + }, + seekbar: { + height: 4, + }, + seekbarThumb: { + position: 'absolute', + bottom: -4, + right: 0, + zIndex: 100, + }, +}); + +/** + * + * + * + * + * + * + * + * + * + * 200 -> 200 * 40% + * + * 180 - 33.33% = 60; + * + * currentStreamDuration * (diff in current and prev) * 100 / prev + * + * 0 |----------| 150 + * prev = 135 + * + * curr = 90 + * + * + * + * + * + * + * + * + * + * //// 2 * 30 = 60 + * 1.5 * 30 = 45 + * + * 180 + * + * 120 + * + * 0 |------____| 100 + * + * + * 200 * 40% = 80 + * + * 200 * 30% = 60 + * + * + * 30*90 + * + * 0 |---------_| 100 + * Prev = 90 + * |------| + * Curr = 60 + * + * 90 - 60 = 30 + * + * seekbackward(80) + */ diff --git a/packages/react-native-room-kit/src/components/HLSSeekforwardControl.tsx b/packages/react-native-room-kit/src/components/HLSSeekforwardControl.tsx new file mode 100644 index 000000000..8ab2b26b6 --- /dev/null +++ b/packages/react-native-room-kit/src/components/HLSSeekforwardControl.tsx @@ -0,0 +1,97 @@ +import { + HMSHLSPlaylistType, + useIsHLSStreamLive, +} from '@100mslive/react-native-hms'; +import type { HMSHLSPlayer } from '@100mslive/react-native-hms'; +import * as React from 'react'; +import { useSelector } from 'react-redux'; +import { GestureDetector, Gesture } from 'react-native-gesture-handler'; + +import { useIsHLSStreamingOn } from '../hooks-sdk'; +import type { RootState } from '../redux'; +import { SeekArrowIcon } from '../Icons'; +import Animated, { + Easing, + cancelAnimation, + interpolate, + runOnJS, + useAnimatedStyle, + useSharedValue, + withTiming, +} from 'react-native-reanimated'; + +export interface HLSSeekforwardControlProps { + playerRef: React.RefObject>; + onPress?: () => void; +} + +const _HLSSeekforwardControl: React.FC = ({ + playerRef, + onPress, +}) => { + const animatedValue = useSharedValue(0); + const isHLSStreamingOn = useIsHLSStreamingOn(); + const isDVRStream = useSelector((state: RootState) => { + return ( + state.hmsStates.room?.hlsStreamingState.variants?.[0]?.playlistType === + HMSHLSPlaylistType.DVR + ); + }); + const isStreamLive = useIsHLSStreamLive(); + + const handdleSeekForward = () => { + onPress?.(); + playerRef.current?.seekForward(10); + }; + + const tapGestureHandler = React.useMemo(() => { + return Gesture.Tap() + .enabled(!isStreamLive) + .onStart(() => { + cancelAnimation(animatedValue); + animatedValue.value = withTiming( + 1, + { duration: 200, easing: Easing.ease }, + (finished) => { + if (finished) { + animatedValue.value = withTiming(0, { + duration: 100, + easing: Easing.ease, + }); + } + } + ); + runOnJS(handdleSeekForward)(); + }); + }, [isStreamLive]); + + const animatedStyle = useAnimatedStyle( + () => ({ + opacity: interpolate(animatedValue.value, [0, 1], [1, 0.8]), + transform: [ + { + rotateZ: `${interpolate(animatedValue.value, [0, 1], [0, 17])} deg`, + }, + ], + }), + [] + ); + + if (!isHLSStreamingOn || !isDVRStream) return null; + + return ( + + + + + + ); +}; + +export const HLSSeekforwardControl = React.memo(_HLSSeekforwardControl); diff --git a/packages/react-native-room-kit/src/components/HMSHLSMessage.tsx b/packages/react-native-room-kit/src/components/HMSHLSMessage.tsx index 23b034b68..803e53fdf 100644 --- a/packages/react-native-room-kit/src/components/HMSHLSMessage.tsx +++ b/packages/react-native-room-kit/src/components/HMSHLSMessage.tsx @@ -8,7 +8,6 @@ import { TouchableOpacity, } from 'react-native'; import type { HMSMessage } from '@100mslive/react-native-hms'; -import { Gesture, GestureDetector } from 'react-native-gesture-handler'; import { useAllowBlockingPeerFromChat, @@ -49,16 +48,14 @@ const _HMSHLSMessage: React.FC = ({ message }) => { const messageSender = message.sender; const hmsRoomStyles = useHMSRoomStyleSheet( - (_theme, typography) => ({ - senderName: { - color: '#ffffff', - fontFamily: `${typography.font_family}-SemiBold`, - textShadowColor: 'rgba(0, 0, 0, 0.5)', - }, - message: { - color: '#ffffff', + (theme, typography) => ({ + regularSurfaceHigh: { fontFamily: `${typography.font_family}-Regular`, - textShadowColor: 'rgba(0, 0, 0, 0.5)', + color: theme.palette.on_surface_high, + }, + semiBoldSurfaceLow: { + fontFamily: `${typography.font_family}-SemiBold`, + color: theme.palette.on_surface_low, }, threeDots: { tintColor: '#ffffff', @@ -98,36 +95,32 @@ const _HMSHLSMessage: React.FC = ({ message }) => { ) : null} - - - {messageSender - ? messageSender.isLocal - ? 'You' - : messageSender.name - : 'Anonymous'} + + + + {messageSender + ? messageSender.isLocal + ? 'You' + : messageSender.name + : 'Anonymous'} + {' '} + + + {message.message} {canTakeAction ? ( - - - - - + + + ) : null} - - - {message.message} - ); }; @@ -136,28 +129,18 @@ export const HMSHLSMessage = React.memo(_HMSHLSMessage); const styles = StyleSheet.create({ container: { - marginTop: 8, + marginTop: 16, width: '100%', }, - nameWrapper: { + messageWrapper: { + flex: 1, flexDirection: 'row', - alignItems: 'center', - }, - senderName: { - flexGrow: 1, - fontSize: 14, - lineHeight: Platform.OS === 'android' ? 20 : undefined, - letterSpacing: 0.1, - textShadowOffset: { height: 1, width: 1 }, - textShadowRadius: 2, }, message: { + flexShrink: 1, fontSize: 14, lineHeight: Platform.OS === 'android' ? 20 : undefined, letterSpacing: 0.25, - marginTop: 2, - textShadowOffset: { height: 0.5, width: 0.5 }, - textShadowRadius: 2, }, threeDots: { width: 20, diff --git a/packages/react-native-room-kit/src/components/HMSHLSMessageList.tsx b/packages/react-native-room-kit/src/components/HMSHLSMessageList.tsx index fad5f4ff2..f9dc81741 100644 --- a/packages/react-native-room-kit/src/components/HMSHLSMessageList.tsx +++ b/packages/react-native-room-kit/src/components/HMSHLSMessageList.tsx @@ -5,8 +5,8 @@ import { FlashList } from '@shopify/flash-list'; import type { HMSMessage } from '@100mslive/react-native-hms'; import type { RootState } from '../redux'; -import { HMSHLSMessage } from './HMSHLSMessage'; import { useIsLandscapeOrientation } from '../utils/dimension'; +import { HMSOverlayMessageView } from './HMSOverlayMessageView'; export const HMSHLSMessageList: React.FC = () => { const { height: windowHeight } = useWindowDimensions(); @@ -19,7 +19,7 @@ export const HMSHLSMessageList: React.FC = () => { ); const _renderItem = React.useCallback((data: { item: HMSMessage }) => { - return ; + return ; }, []); if (messages.length <= 0) { diff --git a/packages/react-native-room-kit/src/components/HMSOverlayMessageView.tsx b/packages/react-native-room-kit/src/components/HMSOverlayMessageView.tsx new file mode 100644 index 000000000..6b4286c35 --- /dev/null +++ b/packages/react-native-room-kit/src/components/HMSOverlayMessageView.tsx @@ -0,0 +1,189 @@ +import * as React from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { + View, + Text, + StyleSheet, + Platform, + TouchableOpacity, +} from 'react-native'; +import type { HMSMessage } from '@100mslive/react-native-hms'; +import { Gesture, GestureDetector } from 'react-native-gesture-handler'; + +import { + useAllowBlockingPeerFromChat, + useAllowPinningMessage, + useHMSRoomStyleSheet, + useModalType, +} from '../hooks-util'; +import { PinIcon, ThreeDotsIcon } from '../Icons'; +import { setSelectedMessageForAction } from '../redux/actions'; +import { ModalTypes } from '../utils/types'; +import type { RootState } from '../redux'; + +interface HMSMessageProps { + message: HMSMessage; +} + +const _HMSOverlayMessageView: React.FC = ({ message }) => { + const dispatch = useDispatch(); + const { handleModalVisibleType } = useModalType(); + const localPeerId = useSelector( + (state: RootState) => state.hmsStates.localPeer?.peerID + ); + + const allowPinningMessage = useAllowPinningMessage(); + const allowPeerBlocking = useAllowBlockingPeerFromChat(); + const canRemoveOthers = useSelector( + (state: RootState) => + !!state.hmsStates.localPeer?.role?.permissions?.removeOthers + ); + + const isPinned = useSelector( + (state: RootState) => + state.messages.pinnedMessages.findIndex( + (pinnedMessage) => pinnedMessage.id === message.messageId + ) >= 0 + ); + + const messageSender = message.sender; + + const hmsRoomStyles = useHMSRoomStyleSheet( + (_theme, typography) => ({ + senderName: { + color: '#ffffff', + fontFamily: `${typography.font_family}-SemiBold`, + textShadowColor: 'rgba(0, 0, 0, 0.5)', + }, + message: { + color: '#ffffff', + fontFamily: `${typography.font_family}-Regular`, + textShadowColor: 'rgba(0, 0, 0, 0.5)', + }, + threeDots: { + tintColor: '#ffffff', + }, + pinnedLabel: { + color: '#ffffff', + }, + }), + [] + ); + + const onThreeDotsPress = () => { + dispatch(setSelectedMessageForAction(message)); + handleModalVisibleType(ModalTypes.MESSAGE_OPTIONS); + }; + + const canTakeAction = + allowPinningMessage || // can pin message, OR + (allowPeerBlocking && + message.sender && + message.sender.peerID !== localPeerId) || // can block peers, OR + (canRemoveOthers && + message.sender && + message.sender.peerID !== localPeerId); // can remove participants + + return ( + + {isPinned ? ( + + + + PINNED + + + ) : null} + + + + {messageSender + ? messageSender.isLocal + ? 'You' + : messageSender.name + : 'Anonymous'} + + + {canTakeAction ? ( + + + + + + ) : null} + + + + {message.message} + + + ); +}; + +export const HMSOverlayMessageView = React.memo(_HMSOverlayMessageView); + +const styles = StyleSheet.create({ + container: { + marginTop: 8, + width: '100%', + }, + nameWrapper: { + flexDirection: 'row', + alignItems: 'center', + }, + senderName: { + flexGrow: 1, + fontSize: 14, + lineHeight: Platform.OS === 'android' ? 20 : undefined, + letterSpacing: 0.1, + textShadowOffset: { height: 1, width: 1 }, + textShadowRadius: 2, + }, + message: { + fontSize: 14, + lineHeight: Platform.OS === 'android' ? 20 : undefined, + letterSpacing: 0.25, + marginTop: 2, + textShadowOffset: { height: 0.5, width: 0.5 }, + textShadowRadius: 2, + }, + threeDots: { + width: 20, + height: 20, + marginLeft: 4, + }, + threeDotsHitSlop: { + left: 12, + right: 12, + top: 12, + bottom: 12, + }, + pinLabelContainer: { + flexDirection: 'row', + alignItems: 'center', + marginBottom: 4, + }, + pinIcon: { + width: 12, + height: 12, + marginRight: 4, + }, + pinnedLabel: { + fontSize: 10, + textTransform: 'uppercase', + lineHeight: 16, + letterSpacing: 1.5, + }, +}); diff --git a/packages/react-native-room-kit/src/components/Participants/ParticipantsList.tsx b/packages/react-native-room-kit/src/components/Participants/ParticipantsList.tsx index b12c229f6..d77a59438 100644 --- a/packages/react-native-room-kit/src/components/Participants/ParticipantsList.tsx +++ b/packages/react-native-room-kit/src/components/Participants/ParticipantsList.tsx @@ -31,7 +31,7 @@ export const ParticipantsList: React.FC = ({ const fetchedInitialDataRef = React.useRef(false); const hmsInstance = useHMSInstance(); - // Currect is current selected group and off-stage gorup + // Current is current selected group and off-stage group const isOffStageGroup = useHMSLayoutConfig((layoutConfig) => { const offStageRoles = layoutConfig?.screens?.conferencing?.default?.elements?.on_stage_exp @@ -39,12 +39,12 @@ export const ParticipantsList: React.FC = ({ return offStageRoles ? offStageRoles.includes(selectedGroupId) : false; }); - // Getting initial data for the selected group Id - const dataForGroupId = useSelector( - (state: RootState) => { - return selectedGroupId === 'hand-raised' ? state.hmsStates.groupedParticipants : state.hmsStates.groupedParticipants[selectedGroupId] - } - ); + // Getting initial data for the selected group ID + const dataForGroupId = useSelector((state: RootState) => { + return selectedGroupId === 'hand-raised' + ? state.hmsStates.groupedParticipants + : state.hmsStates.groupedParticipants[selectedGroupId]; + }); const finalDataForGroupId = React.useMemo(() => { if (Array.isArray(dataForGroupId)) { @@ -52,7 +52,9 @@ export const ParticipantsList: React.FC = ({ } if (dataForGroupId && selectedGroupId === 'hand-raised') { - return Object.values(dataForGroupId).flat().filter(peer => peer.isHandRaised); + return Object.values(dataForGroupId) + .flat() + .filter((peer) => peer.isHandRaised); } return null; @@ -119,7 +121,7 @@ export const ParticipantsList: React.FC = ({ const filteredSearchText = searchText.trim().toLowerCase(); - //#region Flaslist props + //#region FlashList props const data = React.useMemo(() => { return (isOffStageGroup ? offStageData : dataWithHeader).filter((item) => 'id' in item ? true : item.name.toLowerCase().includes(filteredSearchText) @@ -186,7 +188,7 @@ export const ParticipantsList: React.FC = ({ }); } }, [loading, peerListIterator]); - //#endregion Flaslist props + //#endregion FlashList props const searchTextExists = searchText.length > 0; diff --git a/packages/react-native-room-kit/src/hooks-util.ts b/packages/react-native-room-kit/src/hooks-util.ts index cb6cb542c..1a9ca24de 100644 --- a/packages/react-native-room-kit/src/hooks-util.ts +++ b/packages/react-native-room-kit/src/hooks-util.ts @@ -24,10 +24,13 @@ import { WindowController, useHMSHLSPlayerCue, HMSPollUpdateType, + useHMSHLSPlayerPlaybackState, + HMSHLSPlayerPlaybackState, } from '@100mslive/react-native-hms'; import type { Chat as ChatConfig } from '@100mslive/types-prebuilt/elements/chat'; import { SoftInputModes } from '@100mslive/react-native-hms'; import type { + HMSHLSPlayer, HMSPIPConfig, HMSRole, HMSSessionStore, @@ -93,6 +96,7 @@ import { saveUserData, setActiveChatBottomSheetTab, setActiveSpeakers, + setAndroidHLSStreamPaused, setAutoEnterPipMode, setChatPeerBlacklist, setChatState, @@ -3187,7 +3191,7 @@ export const useHLSPlayerConstraints = () => { * Handling Landscape Orientation for both Full and Normal screen */ if (isLandscapeOrientation) { - return sr > 1 || sr > wr + return sr > wr ? { width: wrapperWidth, height: wrapperWidth / sr, @@ -3213,3 +3217,37 @@ export const useHLSPlayerConstraints = () => { height: wrapperHeight, }; }; + +export const useHLSStreamResumePause = ( + playerRef: React.RefObject> +) => { + const dispatch = useDispatch(); + + const isPaused = Platform.select({ + android: useSelector( + (state: RootState) => state.app.hlsStreamPaused_android + ), + ios: useHMSHLSPlayerPlaybackState() === HMSHLSPlayerPlaybackState.PAUSED, + default: false, + }); + + const resumeStream = useCallback(() => { + playerRef.current?.resume(); + if (Platform.OS === 'android') { + dispatch(setAndroidHLSStreamPaused(false)); + } + }, []); + + const pauseStream = useCallback(() => { + playerRef.current?.pause(); + if (Platform.OS === 'android') { + dispatch(setAndroidHLSStreamPaused(true)); + } + }, []); + + return { + isPaused, + resumeStream, + pauseStream, + }; +}; diff --git a/packages/react-native-room-kit/src/redux/actionTypes.ts b/packages/react-native-room-kit/src/redux/actionTypes.ts index 57f0cabe7..4d8979422 100644 --- a/packages/react-native-room-kit/src/redux/actionTypes.ts +++ b/packages/react-native-room-kit/src/redux/actionTypes.ts @@ -113,6 +113,8 @@ const SET_HLS_DESC_PANE_VISIBLE = 'SET_HLS_DESC_PANE_VISIBLE'; const SET_HLS_FULL_SCREEN = 'SET_HLS_FULL_SCREEN'; +const SET_ANDROID_HLS_STREAM_PAUSED = 'SET_ANDROID_HLS_STREAM_PAUSED'; + const FILTER_OUT_BLOCKED_MSGS = 'FILTER_OUT_BLOCKED_MSGS'; export default { @@ -164,6 +166,7 @@ export default { SET_CHAT_PEER_BLACKLIST, SET_HLS_DESC_PANE_VISIBLE, SET_HLS_FULL_SCREEN, + SET_ANDROID_HLS_STREAM_PAUSED, FILTER_OUT_BLOCKED_MSGS, }; diff --git a/packages/react-native-room-kit/src/redux/actions/index.ts b/packages/react-native-room-kit/src/redux/actions/index.ts index d86b550b8..9aa7bfd4e 100644 --- a/packages/react-native-room-kit/src/redux/actions/index.ts +++ b/packages/react-native-room-kit/src/redux/actions/index.ts @@ -486,6 +486,11 @@ export const setHlsFullScreen = (fullScreen: boolean) => ({ payload: { fullScreen }, }); +export const setAndroidHLSStreamPaused = (paused: boolean) => ({ + type: actionTypes.SET_ANDROID_HLS_STREAM_PAUSED, + payload: { hlsStreamPaused_android: paused }, +}); + /** * POLLS */ diff --git a/packages/react-native-room-kit/src/redux/reducers/appState.ts b/packages/react-native-room-kit/src/redux/reducers/appState.ts index 8f7b9848e..58111e484 100644 --- a/packages/react-native-room-kit/src/redux/reducers/appState.ts +++ b/packages/react-native-room-kit/src/redux/reducers/appState.ts @@ -64,6 +64,7 @@ type IntialStateType = { chatPeerBlacklist: string[]; // list of userIds hlsDescriptionPaneVisible: boolean; hlsFullScreen: boolean; + hlsStreamPaused_android: boolean; }; const INITIAL_STATE: IntialStateType = { @@ -103,6 +104,7 @@ const INITIAL_STATE: IntialStateType = { chatPeerBlacklist: [], hlsDescriptionPaneVisible: false, hlsFullScreen: false, + hlsStreamPaused_android: false, }; const appReducer = ( @@ -373,6 +375,12 @@ const appReducer = ( hlsFullScreen: action.payload.fullScreen, }; } + case ActionTypes.SET_ANDROID_HLS_STREAM_PAUSED: { + return { + ...state, + hlsStreamPaused_android: action.payload.hlsStreamPaused_android, + }; + } case HmsStateActionTypes.CLEAR_STATES: return INITIAL_STATE; default: