@100mslive/react-native-hms 1.12.2 → 2.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +70 -12
- package/android/src/main/java/com/reactnativehmssdk/HMSAudioshareActivity.kt +8 -8
- package/android/src/main/java/com/reactnativehmssdk/HMSHLSPlayer.kt +38 -12
- package/android/src/main/java/com/reactnativehmssdk/HMSHLSPlayerManagerImpl.kt +185 -0
- package/android/src/main/java/com/reactnativehmssdk/HMSHelper.kt +20 -10
- package/android/src/main/java/com/reactnativehmssdk/{HMSManager.kt → HMSManagerImpl.kt} +28 -111
- package/android/src/main/java/com/reactnativehmssdk/HMSRNSDK.kt +3 -3
- package/android/src/main/java/com/reactnativehmssdk/HMSReactNativeEvent.kt +29 -0
- package/android/src/main/java/com/reactnativehmssdk/HMSSDKViewManagerImpl.kt +119 -0
- package/android/src/main/java/com/reactnativehmssdk/HMSView.kt +33 -5
- package/android/src/main/java/com/reactnativehmssdk/HmsScreenshareActivity.kt +9 -9
- package/android/src/main/java/com/reactnativehmssdk/HmssdkPackage.kt +42 -3
- package/android/src/newarch/java/com/reactnativehmssdk/HMSHLSPlayerManager.kt +128 -0
- package/android/src/newarch/java/com/reactnativehmssdk/HMSManager.kt +332 -0
- package/android/src/newarch/java/com/reactnativehmssdk/HMSSDKViewManager.kt +102 -0
- package/android/src/oldarch/java/com/reactnativehmssdk/HMSHLSPlayerManager.kt +61 -0
- package/android/src/oldarch/java/com/reactnativehmssdk/HMSManager.kt +351 -0
- package/android/src/oldarch/java/com/reactnativehmssdk/HMSSDKViewManager.kt +87 -0
- package/ios/HMSHLSPlayerComponentView.mm +325 -0
- package/ios/HMSHLSPlayerManager.m +10 -0
- package/ios/HMSHLSPlayerManager.swift +91 -79
- package/ios/HMSManager.m +13 -0
- package/ios/HMSManager.mm +365 -0
- package/ios/HMSManager.swift +109 -103
- package/ios/HMSView.m +9 -0
- package/ios/HMSView.swift +44 -14
- package/ios/HMSViewComponentView.mm +229 -0
- package/lib/commonjs/classes/HmsView.js +45 -48
- package/lib/commonjs/classes/HmsView.js.map +1 -1
- package/lib/commonjs/components/HMSHLSPlayer/HMSHLSPlayer.js +46 -26
- package/lib/commonjs/components/HMSHLSPlayer/HMSHLSPlayer.js.map +1 -1
- package/lib/commonjs/components/HMSHLSPlayer/RCTHMSHLSPlayer.js +5 -4
- package/lib/commonjs/components/HMSHLSPlayer/RCTHMSHLSPlayer.js.map +1 -1
- package/lib/commonjs/modules/HMSManagerModule.js +3 -10
- package/lib/commonjs/modules/HMSManagerModule.js.map +1 -1
- package/lib/commonjs/specs/HMSHLSPlayerNativeComponent.js +75 -0
- package/lib/commonjs/specs/HMSHLSPlayerNativeComponent.js.map +1 -0
- package/lib/commonjs/specs/HMSViewNativeComponent.js +55 -0
- package/lib/commonjs/specs/HMSViewNativeComponent.js.map +1 -0
- package/lib/commonjs/specs/NativeHMSManager.js +38 -0
- package/lib/commonjs/specs/NativeHMSManager.js.map +1 -0
- package/lib/module/classes/HmsView.js +46 -49
- package/lib/module/classes/HmsView.js.map +1 -1
- package/lib/module/components/HMSHLSPlayer/HMSHLSPlayer.js +48 -28
- package/lib/module/components/HMSHLSPlayer/HMSHLSPlayer.js.map +1 -1
- package/lib/module/components/HMSHLSPlayer/RCTHMSHLSPlayer.js +3 -3
- package/lib/module/components/HMSHLSPlayer/RCTHMSHLSPlayer.js.map +1 -1
- package/lib/module/modules/HMSManagerModule.js +1 -9
- package/lib/module/modules/HMSManagerModule.js.map +1 -1
- package/lib/module/specs/HMSHLSPlayerNativeComponent.js +69 -0
- package/lib/module/specs/HMSHLSPlayerNativeComponent.js.map +1 -0
- package/lib/module/specs/HMSViewNativeComponent.js +49 -0
- package/lib/module/specs/HMSViewNativeComponent.js.map +1 -0
- package/lib/module/specs/NativeHMSManager.js +33 -0
- package/lib/module/specs/NativeHMSManager.js.map +1 -0
- package/lib/typescript/components/HMSHLSPlayer/RCTHMSHLSPlayer.d.ts +6 -9
- package/lib/typescript/specs/HMSHLSPlayerNativeComponent.d.ts +115 -0
- package/lib/typescript/specs/HMSViewNativeComponent.d.ts +97 -0
- package/lib/typescript/specs/NativeHMSManager.d.ts +147 -0
- package/package.json +16 -1
- package/react-native-hms.podspec +43 -0
- package/src/classes/HmsView.tsx +60 -78
- package/src/components/HMSHLSPlayer/HMSHLSPlayer.tsx +62 -128
- package/src/components/HMSHLSPlayer/RCTHMSHLSPlayer.ts +8 -13
- package/src/modules/HMSManagerModule.ts +1 -14
- package/src/specs/HMSHLSPlayerNativeComponent.ts +203 -0
- package/src/specs/HMSViewNativeComponent.ts +119 -0
- package/src/specs/NativeHMSManager.ts +307 -0
- package/android/src/main/java/com/reactnativehmssdk/HMSHLSPlayerManager.kt +0 -144
- package/android/src/main/java/com/reactnativehmssdk/HMSSDKViewManager.kt +0 -111
package/android/build.gradle
CHANGED
|
@@ -1,21 +1,34 @@
|
|
|
1
1
|
import groovy.json.JsonSlurper
|
|
2
2
|
|
|
3
|
+
// AGP, Kotlin, and the React Native gradle plugin all come from the consumer
|
|
4
|
+
// app's classloader (root buildscript classpath in legacy consumers, or
|
|
5
|
+
// pluginManagement.includeBuild in modern RN 0.71+ consumers). We deliberately
|
|
6
|
+
// do NOT declare our own `buildscript { dependencies { classpath(...) } }`
|
|
7
|
+
// block: that creates a separate buildscript classloader for this subproject,
|
|
8
|
+
// which causes the React plugin to be loaded twice when another lib in the
|
|
9
|
+
// same build also applies it ("Cannot add extension with name 'privateReact'"
|
|
10
|
+
// — different Class<PrivateReactExtension> objects per classloader fail
|
|
11
|
+
// findByType lookups). Inheriting plugins from the consumer's classpath
|
|
12
|
+
// guarantees a single load.
|
|
13
|
+
plugins {
|
|
14
|
+
id 'com.android.library'
|
|
15
|
+
id 'kotlin-android'
|
|
16
|
+
id 'com.facebook.react'
|
|
17
|
+
}
|
|
18
|
+
|
|
3
19
|
def sdkVersions = new JsonSlurper().parse file("../sdk-versions.json")
|
|
4
20
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
21
|
+
// Helper that mirrors the consumer-app `newArchEnabled` Gradle property.
|
|
22
|
+
// Used by the source-set switch below: when new arch is on, the build
|
|
23
|
+
// pulls in `src/newarch/` Kotlin (TurboModule wrapper extending the
|
|
24
|
+
// generated NativeHMSManagerSpec). When off, it pulls in `src/oldarch/`
|
|
25
|
+
// (legacy wrapper extending ReactContextBaseJavaModule). Either way,
|
|
26
|
+
// `src/main/` always provides the shared HMSManagerImpl with the
|
|
27
|
+
// actual SDK logic.
|
|
28
|
+
def isNewArchitectureEnabled() {
|
|
29
|
+
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
|
|
14
30
|
}
|
|
15
31
|
|
|
16
|
-
apply plugin: 'com.android.library'
|
|
17
|
-
apply plugin: 'kotlin-android'
|
|
18
|
-
|
|
19
32
|
// Define helper functions for Kotlin version management (RN 0.77.3 requires 2.0.21)
|
|
20
33
|
def getKotlinVersion() {
|
|
21
34
|
return rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : "2.0.21"
|
|
@@ -38,6 +51,38 @@ android {
|
|
|
38
51
|
targetSdkVersion safeExtGet('Hmssdk_targetSdkVersion', 35)
|
|
39
52
|
versionCode 1
|
|
40
53
|
versionName "1.0"
|
|
54
|
+
|
|
55
|
+
// Build flag exposed to Kotlin/Java via BuildConfig so runtime
|
|
56
|
+
// code can branch on the active arch if needed (rare — most
|
|
57
|
+
// arch-specific behavior is resolved at compile time via the
|
|
58
|
+
// sourceSets switch below).
|
|
59
|
+
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
buildFeatures {
|
|
63
|
+
buildConfig = true
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Source-set switch — chooses the arch-specific wrapper classes.
|
|
67
|
+
// Both `src/newarch/` and `src/oldarch/` contain the same package
|
|
68
|
+
// and class names (HMSManager, HMSSDKViewManager, HMSHLSPlayerManager);
|
|
69
|
+
// only one is compiled per build, picked here based on the consumer
|
|
70
|
+
// app's `newArchEnabled` Gradle property.
|
|
71
|
+
//
|
|
72
|
+
// The actual SDK business logic lives in `src/main/` as `HMSManagerImpl`,
|
|
73
|
+
// `HMSSDKViewManagerImpl`, etc. Both arch wrappers delegate to it.
|
|
74
|
+
//
|
|
75
|
+
// This pattern is the canonical RN community approach for
|
|
76
|
+
// backward-compatible TurboModules — see:
|
|
77
|
+
// https://github.com/reactwg/react-native-new-architecture/blob/main/docs/backwards-compat-turbo-modules.md
|
|
78
|
+
sourceSets {
|
|
79
|
+
main {
|
|
80
|
+
if (isNewArchitectureEnabled()) {
|
|
81
|
+
java.srcDirs += ['src/newarch']
|
|
82
|
+
} else {
|
|
83
|
+
java.srcDirs += ['src/oldarch']
|
|
84
|
+
}
|
|
85
|
+
}
|
|
41
86
|
}
|
|
42
87
|
|
|
43
88
|
lint {
|
|
@@ -52,6 +97,19 @@ android {
|
|
|
52
97
|
}
|
|
53
98
|
}
|
|
54
99
|
|
|
100
|
+
// Codegen configuration. Consumer's build picks up the TS specs in
|
|
101
|
+
// `src/specs/` and generates:
|
|
102
|
+
// - Java abstract class `NativeHMSManagerSpec` (and others) under
|
|
103
|
+
// the package below, which our `src/newarch/` wrapper extends.
|
|
104
|
+
// - C++ Fabric component descriptors / event emitters / props under
|
|
105
|
+
// `react/renderer/components/RNHmsSpec/...` for iOS-side
|
|
106
|
+
// `*ComponentView.mm` files (see `react-native-hms.podspec`).
|
|
107
|
+
react {
|
|
108
|
+
jsRootDir = file("../src/specs/")
|
|
109
|
+
libraryName = "RNHmsSpec"
|
|
110
|
+
codegenJavaPackageName = "com.reactnativehmssdk"
|
|
111
|
+
}
|
|
112
|
+
|
|
55
113
|
repositories {
|
|
56
114
|
mavenLocal()
|
|
57
115
|
maven {
|
|
@@ -18,17 +18,17 @@ class HMSAudioshareActivity : ComponentActivity() {
|
|
|
18
18
|
val mediaProjectionPermissionResultData: Intent? = result.data
|
|
19
19
|
val id = intent.getStringExtra("id")
|
|
20
20
|
val audioMixingMode = intent.getStringExtra("audioMixingMode")
|
|
21
|
-
|
|
21
|
+
HMSManagerImpl.hmsCollection[id]?.hmsSDK?.startAudioshare(
|
|
22
22
|
object : HMSActionResultListener {
|
|
23
23
|
override fun onError(error: HMSException) {
|
|
24
24
|
finish()
|
|
25
|
-
|
|
25
|
+
HMSManagerImpl.hmsCollection[id]?.audioshareCallback?.reject(error)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
override fun onSuccess() {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
HMSManagerImpl.hmsCollection[id]?.isAudioSharing = true
|
|
30
|
+
HMSManagerImpl.hmsCollection[id]?.audioshareCallback?.resolve(
|
|
31
|
+
HMSManagerImpl.hmsCollection[id]?.getPromiseResolveData(),
|
|
32
32
|
)
|
|
33
33
|
finish()
|
|
34
34
|
}
|
|
@@ -46,7 +46,7 @@ class HMSAudioshareActivity : ComponentActivity() {
|
|
|
46
46
|
"RESULT_CANCELED",
|
|
47
47
|
"RESULT_CANCELED",
|
|
48
48
|
)
|
|
49
|
-
|
|
49
|
+
HMSManagerImpl.hmsCollection[id]?.audioshareCallback?.reject(error)
|
|
50
50
|
finish()
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -58,7 +58,7 @@ class HMSAudioshareActivity : ComponentActivity() {
|
|
|
58
58
|
|
|
59
59
|
private fun startAudioshare() {
|
|
60
60
|
val id = intent.getStringExtra("id")
|
|
61
|
-
val isAudioShared =
|
|
61
|
+
val isAudioShared = HMSManagerImpl.hmsCollection[id]?.isAudioSharing
|
|
62
62
|
if (isAudioShared !== null && !isAudioShared) {
|
|
63
63
|
try {
|
|
64
64
|
val mediaProjectionManager =
|
|
@@ -68,7 +68,7 @@ class HMSAudioshareActivity : ComponentActivity() {
|
|
|
68
68
|
println(e)
|
|
69
69
|
}
|
|
70
70
|
} else {
|
|
71
|
-
|
|
71
|
+
HMSManagerImpl.hmsCollection[id]?.emitHMSError(
|
|
72
72
|
HMSException(
|
|
73
73
|
103,
|
|
74
74
|
"AUDIOSHARE_IS_ALREADY_RUNNING",
|
|
@@ -2,6 +2,7 @@ package com.reactnativehmssdk
|
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.content.Context
|
|
5
|
+
import android.util.Log
|
|
5
6
|
import android.view.LayoutInflater
|
|
6
7
|
import android.view.View
|
|
7
8
|
import android.widget.FrameLayout
|
|
@@ -15,7 +16,7 @@ import com.facebook.react.bridge.ReadableArray
|
|
|
15
16
|
import com.facebook.react.bridge.ReadableMap
|
|
16
17
|
import com.facebook.react.bridge.WritableMap
|
|
17
18
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
18
|
-
import com.facebook.react.uimanager.
|
|
19
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
19
20
|
import live.hms.hls_player.*
|
|
20
21
|
import live.hms.stats.PlayerStatsListener
|
|
21
22
|
import live.hms.stats.model.PlayerStatsModel
|
|
@@ -33,6 +34,11 @@ class HMSHLSPlayer(
|
|
|
33
34
|
private var hmssdkInstance: HMSSDK? = null
|
|
34
35
|
private var statsMonitorAttached = false
|
|
35
36
|
private var shouldSendCaptionsToJS = false
|
|
37
|
+
|
|
38
|
+
// Held so `cleanup()` can remove the listener from ExoPlayer on unmount.
|
|
39
|
+
// The anonymous Player.Listener captures `this`, so leaking it across
|
|
40
|
+
// mount/unmount cycles prevents GC of HMSHLSPlayer view instances.
|
|
41
|
+
private var playerListener: Player.Listener? = null
|
|
36
42
|
private val hmsHlsPlaybackEventsObject =
|
|
37
43
|
object : HmsHlsPlaybackEvents {
|
|
38
44
|
override fun onCue(cue: HmsHlsCue) {
|
|
@@ -139,7 +145,7 @@ class HMSHLSPlayer(
|
|
|
139
145
|
// setting 100ms HLS Player on Exoplayer
|
|
140
146
|
localPlayerView.player = localHmsHlsPlayer.getNativePlayer()
|
|
141
147
|
|
|
142
|
-
|
|
148
|
+
val listener =
|
|
143
149
|
object : Player.Listener {
|
|
144
150
|
override fun onVideoSizeChanged(videoSize: VideoSize) {
|
|
145
151
|
super.onVideoSizeChanged(videoSize)
|
|
@@ -165,14 +171,21 @@ class HMSHLSPlayer(
|
|
|
165
171
|
?.toString()
|
|
166
172
|
sendHLSPlayerCuesEventToJS(ccText)
|
|
167
173
|
}
|
|
168
|
-
}
|
|
169
|
-
|
|
174
|
+
}
|
|
175
|
+
playerListener = listener
|
|
176
|
+
localPlayerView?.player?.addListener(listener)
|
|
170
177
|
}
|
|
171
178
|
|
|
172
179
|
fun cleanup() {
|
|
173
180
|
hmsHlsPlayer?.stop()
|
|
174
181
|
hmsHlsPlayer?.addPlayerEventListener(null)
|
|
175
182
|
hmsHlsPlayer?.setStatsMonitor(null)
|
|
183
|
+
// Remove the ExoPlayer Player.Listener registered in init. Without
|
|
184
|
+
// this, the anonymous listener (which captures `this`) leaks across
|
|
185
|
+
// mount/unmount cycles — visible in long-running video conferencing
|
|
186
|
+
// sessions where users repeatedly join and leave rooms.
|
|
187
|
+
playerListener?.let { listener -> playerView?.player?.removeListener(listener) }
|
|
188
|
+
playerListener = null
|
|
176
189
|
}
|
|
177
190
|
|
|
178
191
|
fun play(url: String?) {
|
|
@@ -300,6 +313,23 @@ class HMSHLSPlayer(
|
|
|
300
313
|
statsMonitorAttached = false
|
|
301
314
|
}
|
|
302
315
|
|
|
316
|
+
private fun dispatchViewEvent(
|
|
317
|
+
eventName: String,
|
|
318
|
+
payload: WritableMap,
|
|
319
|
+
) {
|
|
320
|
+
val reactContext = context as ReactContext
|
|
321
|
+
val surfaceId = UIManagerHelper.getSurfaceId(this)
|
|
322
|
+
val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id)
|
|
323
|
+
if (dispatcher != null) {
|
|
324
|
+
dispatcher.dispatchEvent(HMSReactNativeEvent(surfaceId, id, eventName, payload))
|
|
325
|
+
} else {
|
|
326
|
+
// Bridgeless mode: dispatcher can be null if the view is detaching or
|
|
327
|
+
// the React tag is no longer valid. Log instead of silently dropping
|
|
328
|
+
// so the event loss is debuggable.
|
|
329
|
+
Log.w("HMSHLSPlayer", "Event '$eventName' dropped — dispatcher null for tag $id")
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
303
333
|
private fun sendHLSPlaybackEventToJS(
|
|
304
334
|
eventName: String,
|
|
305
335
|
data: WritableMap,
|
|
@@ -308,8 +338,7 @@ class HMSHLSPlayer(
|
|
|
308
338
|
event.putString("event", eventName)
|
|
309
339
|
event.putMap("data", data)
|
|
310
340
|
|
|
311
|
-
|
|
312
|
-
reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, HMSHLSPlayerConstants.HMS_HLS_PLAYBACK_EVENT, event)
|
|
341
|
+
dispatchViewEvent(HMSHLSPlayerConstants.HMS_HLS_PLAYBACK_EVENT, event)
|
|
313
342
|
}
|
|
314
343
|
|
|
315
344
|
private fun sendHLSStatsEventToJS(
|
|
@@ -320,8 +349,7 @@ class HMSHLSPlayer(
|
|
|
320
349
|
event.putString("event", eventName)
|
|
321
350
|
event.putMap("data", data)
|
|
322
351
|
|
|
323
|
-
|
|
324
|
-
reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, HMSHLSPlayerConstants.HMS_HLS_STATS_EVENT, event)
|
|
352
|
+
dispatchViewEvent(HMSHLSPlayerConstants.HMS_HLS_STATS_EVENT, event)
|
|
325
353
|
}
|
|
326
354
|
|
|
327
355
|
private fun sendHLSDataRequestEventToJS(
|
|
@@ -347,8 +375,7 @@ class HMSHLSPlayer(
|
|
|
347
375
|
event.putNull("data")
|
|
348
376
|
}
|
|
349
377
|
|
|
350
|
-
|
|
351
|
-
reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, HMSHLSPlayerConstants.HLS_DATA_REQUEST_EVENT, event)
|
|
378
|
+
dispatchViewEvent(HMSHLSPlayerConstants.HLS_DATA_REQUEST_EVENT, event)
|
|
352
379
|
}
|
|
353
380
|
|
|
354
381
|
private fun sendHLSPlayerCuesEventToJS(ccText: String?) {
|
|
@@ -360,8 +387,7 @@ class HMSHLSPlayer(
|
|
|
360
387
|
} else {
|
|
361
388
|
event.putNull("data")
|
|
362
389
|
}
|
|
363
|
-
|
|
364
|
-
reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, HMSHLSPlayerConstants.HLS_PLAYER_CUES_EVENT, event)
|
|
390
|
+
dispatchViewEvent(HMSHLSPlayerConstants.HLS_PLAYER_CUES_EVENT, event)
|
|
365
391
|
}
|
|
366
392
|
}
|
|
367
393
|
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
package com.reactnativehmssdk
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReadableArray
|
|
4
|
+
import com.facebook.react.common.MapBuilder
|
|
5
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* HMSHLSPlayerManagerImpl — shared view-manager logic for `<HMSHLSPlayer />`.
|
|
9
|
+
*
|
|
10
|
+
* Phase 1 / 1C-4 of the New Architecture migration. View-manager
|
|
11
|
+
* responsibilities (creating/cleanup, prop dispatch, 13 commands, event
|
|
12
|
+
* registration) live here as static helpers. Arch-specific wrappers at:
|
|
13
|
+
* - android/src/oldarch/.../HMSHLSPlayerManager.kt — paper, @ReactProp + numeric command IDs
|
|
14
|
+
* - android/src/newarch/.../HMSHLSPlayerManager.kt — Fabric, implements the
|
|
15
|
+
* Codegen-generated HMSHLSPlayerManagerInterface for typed prop + command dispatch
|
|
16
|
+
*/
|
|
17
|
+
class HMSHLSPlayerManagerImpl {
|
|
18
|
+
companion object {
|
|
19
|
+
const val REACT_CLASS = "HMSHLSPlayer"
|
|
20
|
+
|
|
21
|
+
fun createViewInstance(reactContext: ThemedReactContext): HMSHLSPlayer = HMSHLSPlayer(reactContext)
|
|
22
|
+
|
|
23
|
+
fun onDropViewInstance(view: HMSHLSPlayer) {
|
|
24
|
+
view.cleanup()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ─────────────────────────────────────────────────────────────────
|
|
28
|
+
// Prop setters
|
|
29
|
+
// ─────────────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
fun setUrl(
|
|
32
|
+
view: HMSHLSPlayer,
|
|
33
|
+
data: String?,
|
|
34
|
+
) = view.play(data)
|
|
35
|
+
|
|
36
|
+
fun setEnableStats(
|
|
37
|
+
view: HMSHLSPlayer,
|
|
38
|
+
data: Boolean,
|
|
39
|
+
) = view.enableStats(data)
|
|
40
|
+
|
|
41
|
+
fun setEnableControls(
|
|
42
|
+
view: HMSHLSPlayer,
|
|
43
|
+
data: Boolean,
|
|
44
|
+
) = view.enableControls(data)
|
|
45
|
+
|
|
46
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47
|
+
// Imperative commands (13)
|
|
48
|
+
// ─────────────────────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
fun play(
|
|
51
|
+
view: HMSHLSPlayer,
|
|
52
|
+
url: String?,
|
|
53
|
+
) = view.play(url)
|
|
54
|
+
|
|
55
|
+
fun stop(view: HMSHLSPlayer) = view.stop()
|
|
56
|
+
|
|
57
|
+
fun pause(view: HMSHLSPlayer) = view.pause()
|
|
58
|
+
|
|
59
|
+
fun resume(view: HMSHLSPlayer) = view.resume()
|
|
60
|
+
|
|
61
|
+
fun seekToLivePosition(view: HMSHLSPlayer) = view.seekToLivePosition()
|
|
62
|
+
|
|
63
|
+
fun seekForward(
|
|
64
|
+
view: HMSHLSPlayer,
|
|
65
|
+
seconds: Double,
|
|
66
|
+
) = view.seekForward(seconds)
|
|
67
|
+
|
|
68
|
+
fun seekBackward(
|
|
69
|
+
view: HMSHLSPlayer,
|
|
70
|
+
seconds: Double,
|
|
71
|
+
) = view.seekBackward(seconds)
|
|
72
|
+
|
|
73
|
+
fun setVolume(
|
|
74
|
+
view: HMSHLSPlayer,
|
|
75
|
+
level: Int,
|
|
76
|
+
) = view.setVolume(level)
|
|
77
|
+
|
|
78
|
+
fun areClosedCaptionSupported(
|
|
79
|
+
view: HMSHLSPlayer,
|
|
80
|
+
requestId: Int,
|
|
81
|
+
) = view.areClosedCaptionSupported(requestId)
|
|
82
|
+
|
|
83
|
+
fun isClosedCaptionEnabled(
|
|
84
|
+
view: HMSHLSPlayer,
|
|
85
|
+
requestId: Int,
|
|
86
|
+
) = view.isClosedCaptionEnabled(requestId)
|
|
87
|
+
|
|
88
|
+
fun enableClosedCaption(view: HMSHLSPlayer) = view.enableClosedCaption()
|
|
89
|
+
|
|
90
|
+
fun disableClosedCaption(view: HMSHLSPlayer) = view.disableClosedCaption()
|
|
91
|
+
|
|
92
|
+
fun getPlayerDurationDetails(
|
|
93
|
+
view: HMSHLSPlayer,
|
|
94
|
+
requestId: Int,
|
|
95
|
+
) = view.getPlayerDurationDetails(requestId)
|
|
96
|
+
|
|
97
|
+
// ─────────────────────────────────────────────────────────────────
|
|
98
|
+
// Paper-side dispatch helpers (used by the oldarch wrapper)
|
|
99
|
+
// ─────────────────────────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Numeric command IDs preserved from the original view manager so
|
|
103
|
+
* paper-side dispatch keeps the same wire protocol.
|
|
104
|
+
*/
|
|
105
|
+
fun getCommandsMap(): Map<String, Int> =
|
|
106
|
+
MapBuilder
|
|
107
|
+
.builder<String, Int>()
|
|
108
|
+
.put("play", 10)
|
|
109
|
+
.put("stop", 20)
|
|
110
|
+
.put("pause", 30)
|
|
111
|
+
.put("resume", 40)
|
|
112
|
+
.put("seekToLivePosition", 50)
|
|
113
|
+
.put("seekForward", 60)
|
|
114
|
+
.put("seekBackward", 70)
|
|
115
|
+
.put("setVolume", 80)
|
|
116
|
+
.put("areClosedCaptionSupported", 90)
|
|
117
|
+
.put("isClosedCaptionEnabled", 100)
|
|
118
|
+
.put("enableClosedCaption", 110)
|
|
119
|
+
.put("disableClosedCaption", 120)
|
|
120
|
+
.put("getPlayerDurationDetails", 130)
|
|
121
|
+
.build()
|
|
122
|
+
|
|
123
|
+
/** Paper command dispatch by numeric ID. */
|
|
124
|
+
fun receiveCommandById(
|
|
125
|
+
view: HMSHLSPlayer,
|
|
126
|
+
commandId: Int,
|
|
127
|
+
args: ReadableArray?,
|
|
128
|
+
) {
|
|
129
|
+
when (commandId) {
|
|
130
|
+
10 -> play(view, args?.getString(0))
|
|
131
|
+
20 -> stop(view)
|
|
132
|
+
30 -> pause(view)
|
|
133
|
+
40 -> resume(view)
|
|
134
|
+
50 -> seekToLivePosition(view)
|
|
135
|
+
60 -> args?.let { seekForward(view, it.getDouble(0)) }
|
|
136
|
+
70 -> args?.let { seekBackward(view, it.getDouble(0)) }
|
|
137
|
+
80 -> args?.let { setVolume(view, it.getInt(0)) }
|
|
138
|
+
90 -> args?.let { areClosedCaptionSupported(view, it.getInt(0)) }
|
|
139
|
+
100 -> args?.let { isClosedCaptionEnabled(view, it.getInt(0)) }
|
|
140
|
+
110 -> enableClosedCaption(view)
|
|
141
|
+
120 -> disableClosedCaption(view)
|
|
142
|
+
130 -> args?.let { getPlayerDurationDetails(view, it.getInt(0)) }
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Fabric command dispatch by string name. */
|
|
147
|
+
fun receiveCommandByName(
|
|
148
|
+
view: HMSHLSPlayer,
|
|
149
|
+
commandName: String,
|
|
150
|
+
args: ReadableArray?,
|
|
151
|
+
) {
|
|
152
|
+
when (commandName) {
|
|
153
|
+
"play" -> play(view, args?.getString(0))
|
|
154
|
+
"stop" -> stop(view)
|
|
155
|
+
"pause" -> pause(view)
|
|
156
|
+
"resume" -> resume(view)
|
|
157
|
+
"seekToLivePosition" -> seekToLivePosition(view)
|
|
158
|
+
"seekForward" -> args?.let { seekForward(view, it.getDouble(0)) }
|
|
159
|
+
"seekBackward" -> args?.let { seekBackward(view, it.getDouble(0)) }
|
|
160
|
+
"setVolume" -> args?.let { setVolume(view, it.getInt(0)) }
|
|
161
|
+
"areClosedCaptionSupported" -> args?.let { areClosedCaptionSupported(view, it.getInt(0)) }
|
|
162
|
+
"isClosedCaptionEnabled" -> args?.let { isClosedCaptionEnabled(view, it.getInt(0)) }
|
|
163
|
+
"enableClosedCaption" -> enableClosedCaption(view)
|
|
164
|
+
"disableClosedCaption" -> disableClosedCaption(view)
|
|
165
|
+
"getPlayerDurationDetails" -> args?.let { getPlayerDurationDetails(view, it.getInt(0)) }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ─────────────────────────────────────────────────────────────────
|
|
170
|
+
// Event registration — 4 events on `<HMSHLSPlayer />`
|
|
171
|
+
// ─────────────────────────────────────────────────────────────────
|
|
172
|
+
|
|
173
|
+
fun getExportedCustomDirectEventTypeConstants(): Map<String, Any> =
|
|
174
|
+
MapBuilder.of(
|
|
175
|
+
HMSHLSPlayerConstants.HMS_HLS_PLAYBACK_EVENT,
|
|
176
|
+
MapBuilder.of("registrationName", "onHmsHlsPlaybackEvent"),
|
|
177
|
+
HMSHLSPlayerConstants.HMS_HLS_STATS_EVENT,
|
|
178
|
+
MapBuilder.of("registrationName", "onHmsHlsStatsEvent"),
|
|
179
|
+
HMSHLSPlayerConstants.HLS_DATA_REQUEST_EVENT,
|
|
180
|
+
MapBuilder.of("registrationName", "onDataReturned"),
|
|
181
|
+
HMSHLSPlayerConstants.HLS_PLAYER_CUES_EVENT,
|
|
182
|
+
MapBuilder.of("registrationName", "onHlsPlayerCuesEvent"),
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -10,7 +10,7 @@ import android.view.PixelCopy
|
|
|
10
10
|
import android.webkit.URLUtil
|
|
11
11
|
import androidx.annotation.RequiresApi
|
|
12
12
|
import com.facebook.react.bridge.*
|
|
13
|
-
import com.facebook.react.uimanager.
|
|
13
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
14
14
|
import hms.webrtc.SurfaceViewRenderer
|
|
15
15
|
import live.hms.video.audio.HMSAudioManager
|
|
16
16
|
import live.hms.video.error.HMSException
|
|
@@ -634,6 +634,20 @@ object HMSHelper {
|
|
|
634
634
|
output.putInt("requestId", -1)
|
|
635
635
|
}
|
|
636
636
|
val reactContext = context as ReactContext
|
|
637
|
+
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
|
|
638
|
+
|
|
639
|
+
// Bridgeless mode: dispatcher can be null if the view is detaching or
|
|
640
|
+
// the React tag is no longer valid. Log instead of silently dropping
|
|
641
|
+
// so the event loss is debuggable.
|
|
642
|
+
fun dispatchCaptureFrameEvent() {
|
|
643
|
+
val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id)
|
|
644
|
+
if (dispatcher != null) {
|
|
645
|
+
dispatcher.dispatchEvent(HMSReactNativeEvent(surfaceId, id, "captureFrame", output))
|
|
646
|
+
} else {
|
|
647
|
+
Log.w("captureSurfaceView", "captureFrame event dropped — dispatcher null for tag $id")
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
637
651
|
try {
|
|
638
652
|
val bitmap: Bitmap =
|
|
639
653
|
Bitmap.createBitmap(surfaceView.width, surfaceView.height, Bitmap.Config.ARGB_8888)
|
|
@@ -649,12 +663,10 @@ object HMSHelper {
|
|
|
649
663
|
val encoded: String = Base64.encodeToString(byteArray, Base64.DEFAULT)
|
|
650
664
|
Log.d("captureSurfaceView", "Base64: $encoded")
|
|
651
665
|
output.putString("result", encoded)
|
|
652
|
-
|
|
653
|
-
.getJSModule(RCTEventEmitter::class.java)
|
|
654
|
-
.receiveEvent(id, "captureFrame", output)
|
|
666
|
+
dispatchCaptureFrameEvent()
|
|
655
667
|
} else {
|
|
656
668
|
Log.e("captureSurfaceView", "copyResult: $copyResult")
|
|
657
|
-
|
|
669
|
+
HMSManagerImpl.hmsCollection[sdkId]?.emitHMSError(
|
|
658
670
|
HMSException(
|
|
659
671
|
103,
|
|
660
672
|
copyResult.toString(),
|
|
@@ -664,18 +676,16 @@ object HMSHelper {
|
|
|
664
676
|
),
|
|
665
677
|
)
|
|
666
678
|
output.putString("error", copyResult.toString())
|
|
667
|
-
|
|
668
|
-
.getJSModule(RCTEventEmitter::class.java)
|
|
669
|
-
.receiveEvent(id, "captureFrame", output)
|
|
679
|
+
dispatchCaptureFrameEvent()
|
|
670
680
|
}
|
|
671
681
|
},
|
|
672
682
|
Handler(),
|
|
673
683
|
)
|
|
674
684
|
} catch (e: Exception) {
|
|
675
685
|
Log.e("captureSurfaceView", "error: $e")
|
|
676
|
-
|
|
686
|
+
HMSManagerImpl.hmsCollection[sdkId]?.emitHMSError(e as HMSException)
|
|
677
687
|
output.putString("error", e.message)
|
|
678
|
-
|
|
688
|
+
dispatchCaptureFrameEvent()
|
|
679
689
|
}
|
|
680
690
|
}
|
|
681
691
|
|