@fishjam-cloud/react-native-client 0.4.0 → 0.5.0
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 +1 -1
- package/android/src/main/java/io/fishjam/reactnative/EmitableEvents.kt +99 -14
- package/android/src/main/java/io/fishjam/reactnative/RNFishjamClient.kt +63 -92
- package/android/src/main/java/io/fishjam/reactnative/RNFishjamClientModule.kt +12 -23
- package/android/src/main/java/io/fishjam/reactnative/VideoRendererViewModule.kt +6 -2
- package/android/src/main/java/io/fishjam/reactnative/VideoView.kt +41 -3
- package/android/src/main/java/io/fishjam/reactnative/extensions/CaptureDevice.kt +17 -0
- package/android/src/main/java/io/fishjam/reactnative/foregroundService/FishjamForegroundService.kt +10 -4
- package/android/src/main/java/io/fishjam/reactnative/foregroundService/ForegroundServiceManager.kt +41 -70
- package/android/src/main/java/io/fishjam/reactnative/foregroundService/ForegroundServiceState.kt +46 -0
- package/android/src/main/java/io/fishjam/reactnative/managers/ListenerManager.kt +22 -0
- package/android/src/main/java/io/fishjam/reactnative/managers/LocalCameraTracksChangedListenersManager.kt +2 -15
- package/android/src/main/java/io/fishjam/reactnative/managers/LocalTracksSwitchListenersManager.kt +1 -11
- package/android/src/main/java/io/fishjam/reactnative/managers/TracksUpdateListenersManager.kt +1 -15
- package/build/RNFishjamClientModule.d.ts +6 -7
- package/build/RNFishjamClientModule.d.ts.map +1 -1
- package/build/RNFishjamClientModule.js.map +1 -1
- package/build/common/client.d.ts +2 -1
- package/build/common/client.d.ts.map +1 -1
- package/build/common/client.js.map +1 -1
- package/build/common/webRTC.d.ts +2 -1
- package/build/common/webRTC.d.ts.map +1 -1
- package/build/common/webRTC.js.map +1 -1
- package/build/components/FishjamRoom/GridTrackItem.d.ts +11 -0
- package/build/components/FishjamRoom/GridTrackItem.d.ts.map +1 -0
- package/build/components/FishjamRoom/GridTrackItem.js +56 -0
- package/build/components/FishjamRoom/GridTrackItem.js.map +1 -0
- package/build/components/FishjamRoom/VideosGrid.d.ts +3 -0
- package/build/components/FishjamRoom/VideosGrid.d.ts.map +1 -0
- package/build/components/FishjamRoom/VideosGrid.js +20 -0
- package/build/components/FishjamRoom/VideosGrid.js.map +1 -0
- package/build/components/FishjamRoom/index.d.ts +6 -0
- package/build/components/FishjamRoom/index.d.ts.map +1 -0
- package/build/components/FishjamRoom/index.js +29 -0
- package/build/components/FishjamRoom/index.js.map +1 -0
- package/build/components/FishjamRoom/parsePeersToTracks.d.ts +4 -0
- package/build/components/FishjamRoom/parsePeersToTracks.d.ts.map +1 -0
- package/build/components/FishjamRoom/parsePeersToTracks.js +36 -0
- package/build/components/FishjamRoom/parsePeersToTracks.js.map +1 -0
- package/build/components/VideoRendererView.d.ts +6 -1
- package/build/components/VideoRendererView.d.ts.map +1 -1
- package/build/components/VideoRendererView.js.map +1 -1
- package/build/hooks/useAppScreenShare.js +1 -1
- package/build/hooks/useAppScreenShare.js.map +1 -1
- package/build/hooks/useCamera.d.ts +6 -2
- package/build/hooks/useCamera.d.ts.map +1 -1
- package/build/hooks/useCamera.js +14 -17
- package/build/hooks/useCamera.js.map +1 -1
- package/build/hooks/useFishjamEvent.d.ts +1 -1
- package/build/hooks/useFishjamEvent.js +1 -1
- package/build/hooks/useFishjamEvent.js.map +1 -1
- package/build/hooks/useFishjamEventState.d.ts +3 -0
- package/build/hooks/useFishjamEventState.d.ts.map +1 -0
- package/build/hooks/useFishjamEventState.js +16 -0
- package/build/hooks/useFishjamEventState.js.map +1 -0
- package/build/hooks/useForegroundService.d.ts +12 -20
- package/build/hooks/useForegroundService.d.ts.map +1 -1
- package/build/hooks/useForegroundService.js +14 -4
- package/build/hooks/useForegroundService.js.map +1 -1
- package/build/hooks/useMicrophone.d.ts.map +1 -1
- package/build/hooks/useMicrophone.js +5 -10
- package/build/hooks/useMicrophone.js.map +1 -1
- package/build/hooks/usePeers.d.ts +50 -11
- package/build/hooks/usePeers.d.ts.map +1 -1
- package/build/hooks/usePeers.js +41 -6
- package/build/hooks/usePeers.js.map +1 -1
- package/build/hooks/useScreenShare.d.ts.map +1 -1
- package/build/hooks/useScreenShare.js +5 -6
- package/build/hooks/useScreenShare.js.map +1 -1
- package/build/index.d.ts +3 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/types.d.ts +1 -1
- package/build/types.d.ts.map +1 -1
- package/build/types.js.map +1 -1
- package/build/utils/errorListener.js +2 -2
- package/build/utils/errorListener.js.map +1 -1
- package/ios/Events.swift +97 -19
- package/ios/RNFishjamClient.podspec +1 -1
- package/ios/RNFishjamClient.swift +74 -109
- package/ios/RNFishjamClientModule.swift +6 -6
- package/ios/Utils/PermissionUtils.swift +16 -0
- package/ios/VideoPreviewView.swift +13 -13
- package/ios/VideoRendererView.swift +28 -25
- package/ios/VideoRendererViewModule.swift +8 -4
- package/ios/extensions/AVCaptureDevice.swift +20 -0
- package/ios/managers/LocalCameraTracksChangedListenersManager.swift +23 -0
- package/ios/managers/TracksUpdateListenersManager.swift +21 -0
- package/package.json +9 -11
package/android/build.gradle
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
package io.fishjam.reactnative
|
|
2
2
|
|
|
3
|
+
import com.fishjamcloud.client.models.SimulcastConfig
|
|
4
|
+
import com.twilio.audioswitch.AudioDevice
|
|
5
|
+
import io.fishjam.reactnative.extensions.LocalCamera
|
|
6
|
+
|
|
3
7
|
@Suppress("ktlint:standard:enum-entry-name-case")
|
|
4
8
|
enum class PeerStatus {
|
|
5
9
|
connecting,
|
|
@@ -8,21 +12,102 @@ enum class PeerStatus {
|
|
|
8
12
|
idle
|
|
9
13
|
}
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
class EmitableEvent private constructor(
|
|
16
|
+
private val event: EventName,
|
|
17
|
+
private val eventContent: Any? = null
|
|
18
|
+
) {
|
|
19
|
+
enum class EventName {
|
|
20
|
+
IsMicrophoneOn,
|
|
21
|
+
IsScreenShareOn,
|
|
22
|
+
SimulcastConfigUpdate,
|
|
23
|
+
PeersUpdate,
|
|
24
|
+
AudioDeviceUpdate,
|
|
25
|
+
BandwidthEstimation,
|
|
26
|
+
ReconnectionRetriesLimitReached,
|
|
27
|
+
ReconnectionStarted,
|
|
28
|
+
Reconnected,
|
|
29
|
+
Warning,
|
|
30
|
+
PeerStatusChanged,
|
|
31
|
+
CurrentCameraChanged
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
val name: String
|
|
35
|
+
get() = event.name
|
|
36
|
+
|
|
37
|
+
val data: Map<String, Any?>
|
|
38
|
+
get() = mapOf(event.name to eventContent)
|
|
24
39
|
|
|
25
40
|
companion object {
|
|
26
|
-
val
|
|
41
|
+
val reconnectionRetriesLimitReached = EmitableEvent(EventName.ReconnectionRetriesLimitReached)
|
|
42
|
+
val reconnectionStarted = EmitableEvent(EventName.ReconnectionStarted)
|
|
43
|
+
val reconnected = EmitableEvent(EventName.Reconnected)
|
|
44
|
+
|
|
45
|
+
fun isMicrophoneOn(enabled: Boolean) = EmitableEvent(EventName.IsMicrophoneOn, enabled)
|
|
46
|
+
|
|
47
|
+
fun isScreenShareOn(enabled: Boolean) = EmitableEvent(EventName.IsScreenShareOn, enabled)
|
|
48
|
+
|
|
49
|
+
fun bandwidthEstimation(estimation: Long) = EmitableEvent(EventName.BandwidthEstimation, estimation.toFloat())
|
|
50
|
+
|
|
51
|
+
fun warning(message: String) = EmitableEvent(EventName.Warning, message)
|
|
52
|
+
|
|
53
|
+
fun peerStatusChanged(peerStatus: PeerStatus) = EmitableEvent(EventName.PeerStatusChanged, peerStatus.name)
|
|
54
|
+
|
|
55
|
+
fun currentCameraChanged(
|
|
56
|
+
localCamera: LocalCamera?,
|
|
57
|
+
isCameraOn: Boolean
|
|
58
|
+
) = EmitableEvent(
|
|
59
|
+
EventName.CurrentCameraChanged,
|
|
60
|
+
mapOf(
|
|
61
|
+
"currentCamera" to localCamera,
|
|
62
|
+
"isCameraOn" to isCameraOn
|
|
63
|
+
)
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
fun simulcastConfigUpdate(simulcastConfig: SimulcastConfig) =
|
|
67
|
+
EmitableEvent(
|
|
68
|
+
EventName.SimulcastConfigUpdate,
|
|
69
|
+
mapOf(
|
|
70
|
+
"enabled" to simulcastConfig.enabled,
|
|
71
|
+
"activeEncodings" to simulcastConfig.activeEncodings.map { it.rid }
|
|
72
|
+
)
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
fun peersUpdate(peersData: List<Map<String, Any?>>) = EmitableEvent(EventName.PeersUpdate, peersData)
|
|
76
|
+
|
|
77
|
+
fun audioDeviceUpdate(
|
|
78
|
+
audioDevices: List<AudioDevice>,
|
|
79
|
+
selectedDevice: AudioDevice?
|
|
80
|
+
): EmitableEvent {
|
|
81
|
+
val audioDeviceAsMap = { audioDevice: AudioDevice ->
|
|
82
|
+
mapOf(
|
|
83
|
+
"name" to audioDevice.name,
|
|
84
|
+
"type" to AudioDeviceKind.fromAudioDevice(audioDevice)?.typeName
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return EmitableEvent(
|
|
89
|
+
EventName.AudioDeviceUpdate,
|
|
90
|
+
mapOf(
|
|
91
|
+
"selectedDevice" to (
|
|
92
|
+
if (selectedDevice != null) {
|
|
93
|
+
audioDeviceAsMap(
|
|
94
|
+
selectedDevice
|
|
95
|
+
)
|
|
96
|
+
} else {
|
|
97
|
+
null
|
|
98
|
+
}
|
|
99
|
+
),
|
|
100
|
+
"availableDevices" to
|
|
101
|
+
audioDevices.map { audioDevice ->
|
|
102
|
+
audioDeviceAsMap(
|
|
103
|
+
audioDevice
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
val allEvents: Array<String>
|
|
111
|
+
get() = EventName.entries.map { it.name }.toTypedArray()
|
|
27
112
|
}
|
|
28
113
|
}
|
|
@@ -7,6 +7,8 @@ import android.media.projection.MediaProjectionManager
|
|
|
7
7
|
import androidx.appcompat.app.AppCompatActivity
|
|
8
8
|
import com.fishjamcloud.client.FishjamClient
|
|
9
9
|
import com.fishjamcloud.client.FishjamClientListener
|
|
10
|
+
import com.fishjamcloud.client.media.CaptureDevice
|
|
11
|
+
import com.fishjamcloud.client.media.CaptureDeviceChangedListener
|
|
10
12
|
import com.fishjamcloud.client.media.LocalAudioTrack
|
|
11
13
|
import com.fishjamcloud.client.media.LocalScreenShareTrack
|
|
12
14
|
import com.fishjamcloud.client.media.LocalVideoTrack
|
|
@@ -27,6 +29,7 @@ import com.twilio.audioswitch.AudioDevice
|
|
|
27
29
|
import expo.modules.kotlin.AppContext
|
|
28
30
|
import expo.modules.kotlin.Promise
|
|
29
31
|
import expo.modules.kotlin.exception.CodedException
|
|
32
|
+
import io.fishjam.reactnative.extensions.toLocalCamera
|
|
30
33
|
import io.fishjam.reactnative.foregroundService.ForegroundServiceManager
|
|
31
34
|
import io.fishjam.reactnative.managers.LocalCameraTracksChangedListenersManager
|
|
32
35
|
import io.fishjam.reactnative.managers.LocalTracksSwitchListenersManager
|
|
@@ -40,7 +43,8 @@ import org.webrtc.Logging
|
|
|
40
43
|
|
|
41
44
|
class RNFishjamClient(
|
|
42
45
|
val sendEvent: (name: String, data: Map<String, Any?>) -> Unit
|
|
43
|
-
) : FishjamClientListener
|
|
46
|
+
) : FishjamClientListener,
|
|
47
|
+
CaptureDeviceChangedListener {
|
|
44
48
|
private val SCREENSHARE_REQUEST = 1
|
|
45
49
|
|
|
46
50
|
var isMicrophoneOn = false
|
|
@@ -71,11 +75,12 @@ class RNFishjamClient(
|
|
|
71
75
|
var peerStatus = PeerStatus.idle
|
|
72
76
|
private set(value) {
|
|
73
77
|
field = value
|
|
74
|
-
|
|
75
|
-
emitEvent(event, mapOf(event.name to value))
|
|
78
|
+
emitEvent(EmitableEvent.peerStatusChanged(value))
|
|
76
79
|
}
|
|
77
80
|
|
|
78
|
-
private
|
|
81
|
+
private val foregroundServiceManager by lazy {
|
|
82
|
+
ForegroundServiceManager(appContext ?: throw CodedException("appContext not found"))
|
|
83
|
+
}
|
|
79
84
|
|
|
80
85
|
companion object {
|
|
81
86
|
val trackUpdateListenersManager = TracksUpdateListenersManager()
|
|
@@ -254,7 +259,7 @@ class RNFishjamClient(
|
|
|
254
259
|
com.fishjamcloud.client.ConnectConfig(
|
|
255
260
|
url,
|
|
256
261
|
peerToken,
|
|
257
|
-
|
|
262
|
+
peerMetadata,
|
|
258
263
|
ReconnectConfig(
|
|
259
264
|
config.reconnectConfig.maxAttempts,
|
|
260
265
|
config.reconnectConfig.initialDelayMs,
|
|
@@ -278,20 +283,22 @@ class RNFishjamClient(
|
|
|
278
283
|
}
|
|
279
284
|
}
|
|
280
285
|
|
|
281
|
-
suspend fun startCamera(config: CameraConfig) {
|
|
286
|
+
suspend fun startCamera(config: CameraConfig): Boolean {
|
|
282
287
|
if (isCameraInitialized) {
|
|
283
|
-
|
|
284
|
-
return
|
|
288
|
+
emitEvent(EmitableEvent.warning("Camera already started. You may only call startCamera once before leaveRoom is called."))
|
|
289
|
+
return true
|
|
285
290
|
}
|
|
286
291
|
if (!PermissionUtils.requestCameraPermission(appContext)) {
|
|
287
|
-
|
|
288
|
-
return
|
|
292
|
+
emitEvent(EmitableEvent.warning("Camera permission not granted."))
|
|
293
|
+
return false
|
|
289
294
|
}
|
|
290
295
|
|
|
291
296
|
val cameraTrack = createCameraTrack(config)
|
|
297
|
+
cameraTrack.captureDeviceChangedListener = this
|
|
292
298
|
setCameraTrackState(cameraTrack, config.cameraEnabled)
|
|
293
299
|
emitEndpoints()
|
|
294
300
|
isCameraInitialized = true
|
|
301
|
+
return true
|
|
295
302
|
}
|
|
296
303
|
|
|
297
304
|
private suspend fun createCameraTrack(config: CameraConfig): LocalVideoTrack {
|
|
@@ -310,8 +317,7 @@ class RNFishjamClient(
|
|
|
310
317
|
) {
|
|
311
318
|
cameraTrack.setEnabled(isEnabled)
|
|
312
319
|
isCameraOn = isEnabled
|
|
313
|
-
|
|
314
|
-
emitEvent(event, mapOf(event.name to isEnabled))
|
|
320
|
+
emitEvent(EmitableEvent.currentCameraChanged(cameraTrack.getCaptureDevice()?.toLocalCamera(), isEnabled))
|
|
315
321
|
localCameraTracksChangedListenersManager.notifyListeners()
|
|
316
322
|
}
|
|
317
323
|
|
|
@@ -337,7 +343,7 @@ class RNFishjamClient(
|
|
|
337
343
|
|
|
338
344
|
private suspend fun startMicrophone() {
|
|
339
345
|
if (!PermissionUtils.requestMicrophonePermission(appContext)) {
|
|
340
|
-
|
|
346
|
+
emitEvent(EmitableEvent.warning("Microphone permission not granted."))
|
|
341
347
|
return
|
|
342
348
|
}
|
|
343
349
|
|
|
@@ -352,8 +358,7 @@ class RNFishjamClient(
|
|
|
352
358
|
) {
|
|
353
359
|
microphoneTrack.setEnabled(isEnabled)
|
|
354
360
|
isMicrophoneOn = isEnabled
|
|
355
|
-
|
|
356
|
-
emitEvent(event, mapOf(event.name to isEnabled))
|
|
361
|
+
emitEvent(EmitableEvent.isMicrophoneOn(isEnabled))
|
|
357
362
|
}
|
|
358
363
|
|
|
359
364
|
suspend fun toggleMicrophone(): Boolean {
|
|
@@ -362,6 +367,15 @@ class RNFishjamClient(
|
|
|
362
367
|
} else {
|
|
363
368
|
getLocalAudioTrack()?.let { setMicrophoneTrackState(it, !isMicrophoneOn) }
|
|
364
369
|
}
|
|
370
|
+
|
|
371
|
+
updateLocalAudioTrackMetadata(
|
|
372
|
+
mapOf(
|
|
373
|
+
"active" to isMicrophoneOn,
|
|
374
|
+
"paused" to !isMicrophoneOn, // TODO: FCE-711,
|
|
375
|
+
"type" to "microphone"
|
|
376
|
+
)
|
|
377
|
+
)
|
|
378
|
+
|
|
365
379
|
return isMicrophoneOn
|
|
366
380
|
}
|
|
367
381
|
|
|
@@ -380,22 +394,13 @@ class RNFishjamClient(
|
|
|
380
394
|
}
|
|
381
395
|
}
|
|
382
396
|
|
|
383
|
-
fun
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
suspend fun startForegroundService(config: ForegroundServicePermissionsConfig) {
|
|
390
|
-
if (foregroundServiceManager == null) {
|
|
391
|
-
throw CodedException("Foreground service not configured.")
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
foregroundServiceManager?.startForegroundService(config)
|
|
397
|
+
suspend fun startForegroundService(config: ForegroundServiceConfig) {
|
|
398
|
+
foregroundServiceManager.updateServiceWithConfig(config)
|
|
399
|
+
foregroundServiceManager.start()
|
|
395
400
|
}
|
|
396
401
|
|
|
397
402
|
fun stopForegroundService() {
|
|
398
|
-
foregroundServiceManager
|
|
403
|
+
foregroundServiceManager.stop()
|
|
399
404
|
}
|
|
400
405
|
|
|
401
406
|
suspend fun toggleScreenShare(screenShareOptions: ScreenShareOptions) {
|
|
@@ -408,6 +413,7 @@ class RNFishjamClient(
|
|
|
408
413
|
screenShareOptions.maxBandwidthMap,
|
|
409
414
|
screenShareOptions.maxBandwidthInt
|
|
410
415
|
)
|
|
416
|
+
|
|
411
417
|
if (!isScreenShareOn) {
|
|
412
418
|
ensureConnected()
|
|
413
419
|
startScreenShare()
|
|
@@ -421,7 +427,6 @@ class RNFishjamClient(
|
|
|
421
427
|
mapOf(
|
|
422
428
|
"id" to endpoint.id,
|
|
423
429
|
"isLocal" to (endpoint.id == fishjamClient.getLocalEndpoint().id),
|
|
424
|
-
"type" to endpoint.type,
|
|
425
430
|
"metadata" to endpoint.metadata,
|
|
426
431
|
"tracks" to
|
|
427
432
|
endpoint.tracks.values.mapNotNull { track ->
|
|
@@ -475,19 +480,12 @@ class RNFishjamClient(
|
|
|
475
480
|
fun getCaptureDevices(): List<Map<String, Any>> {
|
|
476
481
|
val devices = LocalVideoTrack.getCaptureDevices(appContext?.reactContext!!)
|
|
477
482
|
return devices.map { device ->
|
|
478
|
-
|
|
479
|
-
"id" to device.deviceName,
|
|
480
|
-
"name" to device.deviceName,
|
|
481
|
-
"facingDirection" to
|
|
482
|
-
when (true) {
|
|
483
|
-
device.isFrontFacing -> "front"
|
|
484
|
-
device.isBackFacing -> "back"
|
|
485
|
-
else -> "unspecified"
|
|
486
|
-
}
|
|
487
|
-
)
|
|
483
|
+
device.toLocalCamera()
|
|
488
484
|
}
|
|
489
485
|
}
|
|
490
486
|
|
|
487
|
+
fun getCurrentCaptureDevice(): Map<String, Any>? = getLocalVideoTrack()?.getCaptureDevice()?.toLocalCamera()
|
|
488
|
+
|
|
491
489
|
fun updatePeerMetadata(metadata: Metadata) {
|
|
492
490
|
ensureConnected()
|
|
493
491
|
fishjamClient.updatePeerMetadata(metadata)
|
|
@@ -508,7 +506,7 @@ class RNFishjamClient(
|
|
|
508
506
|
}
|
|
509
507
|
}
|
|
510
508
|
|
|
511
|
-
fun updateLocalAudioTrackMetadata(metadata: Metadata) {
|
|
509
|
+
private fun updateLocalAudioTrackMetadata(metadata: Metadata) {
|
|
512
510
|
ensureAudioTrack()
|
|
513
511
|
getLocalAudioTrack()?.let {
|
|
514
512
|
updateTrackMetadata(it.id(), metadata)
|
|
@@ -606,13 +604,15 @@ class RNFishjamClient(
|
|
|
606
604
|
fishjamClient.setTargetTrackEncoding(trackId, encoding.toTrackEncoding())
|
|
607
605
|
}
|
|
608
606
|
|
|
609
|
-
fun toggleVideoTrackEncoding(encoding: String): Map<String, Any
|
|
607
|
+
fun toggleVideoTrackEncoding(encoding: String): Map<String, Any?> {
|
|
610
608
|
ensureVideoTrack()
|
|
611
609
|
val trackId = getLocalVideoTrack()?.id() ?: return emptyMap()
|
|
612
610
|
videoSimulcastConfig = toggleTrackEncoding(encoding, trackId, videoSimulcastConfig)
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
611
|
+
|
|
612
|
+
val event = EmitableEvent.simulcastConfigUpdate(videoSimulcastConfig)
|
|
613
|
+
emitEvent(event)
|
|
614
|
+
|
|
615
|
+
return event.data
|
|
616
616
|
}
|
|
617
617
|
|
|
618
618
|
fun setVideoTrackEncodingBandwidth(
|
|
@@ -712,6 +712,10 @@ class RNFishjamClient(
|
|
|
712
712
|
if (mediaProjectionIntent == null) {
|
|
713
713
|
throw MissingScreenSharePermission()
|
|
714
714
|
}
|
|
715
|
+
|
|
716
|
+
foregroundServiceManager.updateService { screenSharingEnabled = true }
|
|
717
|
+
foregroundServiceManager.start()
|
|
718
|
+
|
|
715
719
|
fishjamClient.createScreenShareTrack(
|
|
716
720
|
mediaProjectionIntent!!,
|
|
717
721
|
videoParameters,
|
|
@@ -743,13 +747,14 @@ class RNFishjamClient(
|
|
|
743
747
|
|
|
744
748
|
private fun setScreenShareTrackState(isEnabled: Boolean) {
|
|
745
749
|
isScreenShareOn = isEnabled
|
|
746
|
-
|
|
747
|
-
emitEvent(event, mapOf(event.name to isEnabled))
|
|
750
|
+
emitEvent(EmitableEvent.isScreenShareOn(isEnabled))
|
|
748
751
|
}
|
|
749
752
|
|
|
750
753
|
private fun stopScreenShare() {
|
|
751
754
|
ensureScreenShareTrack()
|
|
752
755
|
coroutineScope.launch {
|
|
756
|
+
foregroundServiceManager.updateService { screenSharingEnabled = false }
|
|
757
|
+
foregroundServiceManager.start()
|
|
753
758
|
val screenShareTrack =
|
|
754
759
|
fishjamClient.getLocalEndpoint().tracks.values.first { track ->
|
|
755
760
|
track is LocalScreenShareTrack
|
|
@@ -762,58 +767,21 @@ class RNFishjamClient(
|
|
|
762
767
|
}
|
|
763
768
|
}
|
|
764
769
|
|
|
765
|
-
private fun emitEvent(
|
|
766
|
-
event: EmitableEvents,
|
|
767
|
-
data: Map<String, Any?> = mapOf()
|
|
768
|
-
) {
|
|
770
|
+
private fun emitEvent(event: EmitableEvent) {
|
|
769
771
|
CoroutineScope(Dispatchers.Main).launch {
|
|
770
|
-
sendEvent(event.name, data)
|
|
772
|
+
sendEvent(event.name, event.data)
|
|
771
773
|
}
|
|
772
774
|
}
|
|
773
775
|
|
|
774
|
-
fun emitWarning(warning: String) {
|
|
775
|
-
emitEvent(EmitableEvents.Warning, mapOf("message" to warning))
|
|
776
|
-
}
|
|
777
|
-
|
|
778
776
|
private fun emitEndpoints() {
|
|
779
|
-
|
|
780
|
-
emitEvent(event, mapOf(event.name to getPeers()))
|
|
777
|
+
emitEvent(EmitableEvent.peersUpdate(getPeers()))
|
|
781
778
|
}
|
|
782
779
|
|
|
783
|
-
private fun audioDeviceAsRNMap(audioDevice: AudioDevice): Map<String, String?> =
|
|
784
|
-
mapOf(
|
|
785
|
-
"name" to audioDevice.name,
|
|
786
|
-
"type" to AudioDeviceKind.fromAudioDevice(audioDevice)?.typeName
|
|
787
|
-
)
|
|
788
|
-
|
|
789
780
|
private fun emitAudioDeviceEvent(
|
|
790
781
|
audioDevices: List<AudioDevice>,
|
|
791
782
|
selectedDevice: AudioDevice?
|
|
792
783
|
) {
|
|
793
|
-
|
|
794
|
-
emitEvent(
|
|
795
|
-
event,
|
|
796
|
-
mapOf(
|
|
797
|
-
event.name to
|
|
798
|
-
mapOf(
|
|
799
|
-
"selectedDevice" to (
|
|
800
|
-
if (selectedDevice != null) {
|
|
801
|
-
audioDeviceAsRNMap(
|
|
802
|
-
selectedDevice
|
|
803
|
-
)
|
|
804
|
-
} else {
|
|
805
|
-
null
|
|
806
|
-
}
|
|
807
|
-
),
|
|
808
|
-
"availableDevices" to
|
|
809
|
-
audioDevices.map { audioDevice ->
|
|
810
|
-
audioDeviceAsRNMap(
|
|
811
|
-
audioDevice
|
|
812
|
-
)
|
|
813
|
-
}
|
|
814
|
-
)
|
|
815
|
-
)
|
|
816
|
-
)
|
|
784
|
+
emitEvent(EmitableEvent.audioDeviceUpdate(audioDevices, selectedDevice))
|
|
817
785
|
}
|
|
818
786
|
|
|
819
787
|
private fun getSimulcastConfigAsRNMap(simulcastConfig: SimulcastConfig): Map<String, Any> =
|
|
@@ -885,8 +853,7 @@ class RNFishjamClient(
|
|
|
885
853
|
override fun onPeerUpdated(peer: Peer) {}
|
|
886
854
|
|
|
887
855
|
override fun onBandwidthEstimationChanged(estimation: Long) {
|
|
888
|
-
|
|
889
|
-
emitEvent(event, mapOf(event.name to estimation.toFloat()))
|
|
856
|
+
emitEvent(EmitableEvent.bandwidthEstimation(estimation))
|
|
890
857
|
}
|
|
891
858
|
|
|
892
859
|
override fun onDisconnected() {
|
|
@@ -912,14 +879,18 @@ class RNFishjamClient(
|
|
|
912
879
|
}
|
|
913
880
|
|
|
914
881
|
override fun onReconnected() {
|
|
915
|
-
emitEvent(
|
|
882
|
+
emitEvent(EmitableEvent.reconnected)
|
|
916
883
|
}
|
|
917
884
|
|
|
918
885
|
override fun onReconnectionStarted() {
|
|
919
|
-
emitEvent(
|
|
886
|
+
emitEvent(EmitableEvent.reconnectionStarted)
|
|
920
887
|
}
|
|
921
888
|
|
|
922
889
|
override fun onReconnectionRetriesLimitReached() {
|
|
923
|
-
emitEvent(
|
|
890
|
+
emitEvent(EmitableEvent.reconnectionRetriesLimitReached)
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
override fun onCaptureDeviceChanged(captureDevice: CaptureDevice?) {
|
|
894
|
+
emitEvent(EmitableEvent.currentCameraChanged(captureDevice?.toLocalCamera(), isCameraOn))
|
|
924
895
|
}
|
|
925
896
|
}
|
|
@@ -81,7 +81,7 @@ class ConnectConfig : Record {
|
|
|
81
81
|
val reconnectConfig: ReconnectConfig = ReconnectConfig()
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
class
|
|
84
|
+
class ForegroundServiceConfig : Record {
|
|
85
85
|
@Field
|
|
86
86
|
val channelId: String? = null
|
|
87
87
|
|
|
@@ -93,17 +93,12 @@ class ForegroundServiceNotificationConfig : Record {
|
|
|
93
93
|
|
|
94
94
|
@Field
|
|
95
95
|
val notificationTitle: String? = null
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
class ForegroundServicePermissionsConfig : Record {
|
|
99
|
-
@Field
|
|
100
|
-
val enableCamera: Boolean = false
|
|
101
96
|
|
|
102
97
|
@Field
|
|
103
|
-
val
|
|
98
|
+
val enableCamera: Boolean? = null
|
|
104
99
|
|
|
105
100
|
@Field
|
|
106
|
-
val
|
|
101
|
+
val enableMicrophone: Boolean? = null
|
|
107
102
|
}
|
|
108
103
|
|
|
109
104
|
class RNFishjamClientModule : Module() {
|
|
@@ -118,7 +113,7 @@ class RNFishjamClientModule : Module() {
|
|
|
118
113
|
|
|
119
114
|
Name("RNFishjamClient")
|
|
120
115
|
|
|
121
|
-
Events(
|
|
116
|
+
Events(EmitableEvent.allEvents)
|
|
122
117
|
|
|
123
118
|
OnCreate {
|
|
124
119
|
rnFishjamClient.onModuleCreate(appContext)
|
|
@@ -148,6 +143,10 @@ class RNFishjamClientModule : Module() {
|
|
|
148
143
|
return@Property rnFishjamClient.getCaptureDevices()
|
|
149
144
|
}
|
|
150
145
|
|
|
146
|
+
Property("currentCamera") {
|
|
147
|
+
return@Property rnFishjamClient.getCurrentCaptureDevice()
|
|
148
|
+
}
|
|
149
|
+
|
|
151
150
|
Property("isScreenShareOn") {
|
|
152
151
|
return@Property rnFishjamClient.isScreenShareOn
|
|
153
152
|
}
|
|
@@ -171,8 +170,8 @@ class RNFishjamClientModule : Module() {
|
|
|
171
170
|
}
|
|
172
171
|
|
|
173
172
|
AsyncFunction("startCamera") Coroutine { config: CameraConfig ->
|
|
174
|
-
withContext(Dispatchers.Main) {
|
|
175
|
-
rnFishjamClient.startCamera(config)
|
|
173
|
+
return@Coroutine withContext(Dispatchers.Main) {
|
|
174
|
+
return@withContext rnFishjamClient.startCamera(config)
|
|
176
175
|
}
|
|
177
176
|
}
|
|
178
177
|
|
|
@@ -234,12 +233,6 @@ class RNFishjamClientModule : Module() {
|
|
|
234
233
|
}
|
|
235
234
|
}
|
|
236
235
|
|
|
237
|
-
AsyncFunction("updateAudioTrackMetadata") Coroutine { metadata: Map<String, Any> ->
|
|
238
|
-
withContext(Dispatchers.Main) {
|
|
239
|
-
rnFishjamClient.updateLocalAudioTrackMetadata(metadata)
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
236
|
AsyncFunction("updateScreenShareTrackMetadata") Coroutine { metadata: Map<String, Any> ->
|
|
244
237
|
withContext(Dispatchers.Main) {
|
|
245
238
|
rnFishjamClient.updateLocalScreenShareTrackMetadata(metadata)
|
|
@@ -301,18 +294,14 @@ class RNFishjamClientModule : Module() {
|
|
|
301
294
|
}
|
|
302
295
|
|
|
303
296
|
AsyncFunction("changeWebRTCLoggingSeverity") Coroutine { severity: String ->
|
|
304
|
-
|
|
297
|
+
withContext(Dispatchers.Main) {
|
|
305
298
|
rnFishjamClient.changeWebRTCLoggingSeverity(severity)
|
|
306
299
|
}
|
|
307
300
|
}
|
|
308
301
|
|
|
309
302
|
AsyncFunction("getStatistics") { rnFishjamClient.getStatistics() }
|
|
310
303
|
|
|
311
|
-
|
|
312
|
-
return@Function rnFishjamClient.configureForegroundService(config)
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
AsyncFunction("startForegroundService") Coroutine { config: ForegroundServicePermissionsConfig ->
|
|
304
|
+
AsyncFunction("startForegroundService") Coroutine { config: ForegroundServiceConfig ->
|
|
316
305
|
rnFishjamClient.startForegroundService(config)
|
|
317
306
|
}
|
|
318
307
|
|
|
@@ -15,13 +15,17 @@ class VideoRendererViewModule : Module() {
|
|
|
15
15
|
RNFishjamClient.localTracksSwitchListenerManager.remove(view)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
Prop("trackId") { view
|
|
18
|
+
Prop("trackId") { view, trackId: String ->
|
|
19
19
|
view.init(trackId)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
Prop("videoLayout") { view
|
|
22
|
+
Prop("videoLayout") { view, videoLayout: String ->
|
|
23
23
|
view.setVideoLayout(videoLayout)
|
|
24
24
|
}
|
|
25
|
+
|
|
26
|
+
Prop("skipRenderOutsideVisibleArea") { view, skipRenderOutsideVisibleArea: Boolean ->
|
|
27
|
+
view.checkVisibilityDelayMillis = if (skipRenderOutsideVisibleArea) 1000 else null
|
|
28
|
+
}
|
|
25
29
|
}
|
|
26
30
|
}
|
|
27
31
|
}
|
|
@@ -2,16 +2,18 @@ package io.fishjam.reactnative
|
|
|
2
2
|
|
|
3
3
|
import android.animation.ValueAnimator
|
|
4
4
|
import android.content.Context
|
|
5
|
+
import android.content.res.Resources
|
|
5
6
|
import android.graphics.Color
|
|
7
|
+
import android.graphics.Rect
|
|
6
8
|
import android.graphics.drawable.ColorDrawable
|
|
9
|
+
import android.os.Handler
|
|
10
|
+
import android.os.Looper
|
|
7
11
|
import android.view.animation.LinearInterpolator
|
|
8
12
|
import com.fishjamcloud.client.media.LocalVideoTrack
|
|
9
13
|
import com.fishjamcloud.client.media.VideoTrack
|
|
10
14
|
import expo.modules.kotlin.AppContext
|
|
11
15
|
import expo.modules.kotlin.views.ExpoView
|
|
12
16
|
import io.fishjam.reactnative.managers.LocalTrackSwitchListener
|
|
13
|
-
import kotlinx.coroutines.CoroutineScope
|
|
14
|
-
import kotlinx.coroutines.Dispatchers
|
|
15
17
|
import kotlinx.coroutines.delay
|
|
16
18
|
import org.webrtc.RendererCommon
|
|
17
19
|
|
|
@@ -35,7 +37,41 @@ abstract class VideoView(
|
|
|
35
37
|
}
|
|
36
38
|
}
|
|
37
39
|
|
|
38
|
-
val
|
|
40
|
+
private val checkVisibilityHandler: Handler = Handler(Looper.getMainLooper())
|
|
41
|
+
|
|
42
|
+
// If set to `null` the view will always be rendered
|
|
43
|
+
var checkVisibilityDelayMillis: Long? = null
|
|
44
|
+
set(value) {
|
|
45
|
+
field = value
|
|
46
|
+
if (value == null) {
|
|
47
|
+
getVideoTrack()?.shouldReceive(true)
|
|
48
|
+
} else {
|
|
49
|
+
checkVisibilityHandler.post(checkVisibility)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private val checkVisibility =
|
|
54
|
+
object : Runnable {
|
|
55
|
+
override fun run() {
|
|
56
|
+
checkVisibilityDelayMillis?.let {
|
|
57
|
+
getVideoTrack()?.shouldReceive(isVisibleOnScreen)
|
|
58
|
+
checkVisibilityHandler.postDelayed(this, it)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private val isVisibleOnScreen: Boolean
|
|
64
|
+
get() {
|
|
65
|
+
if (!isShown) {
|
|
66
|
+
return false
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
val globalVisibleRect = Rect()
|
|
70
|
+
getGlobalVisibleRect(globalVisibleRect)
|
|
71
|
+
val displayMetrics = Resources.getSystem().displayMetrics
|
|
72
|
+
val screen = Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels)
|
|
73
|
+
return screen.intersect(globalVisibleRect)
|
|
74
|
+
}
|
|
39
75
|
|
|
40
76
|
init {
|
|
41
77
|
RNFishjamClient.localTracksSwitchListenerManager.add(this)
|
|
@@ -53,6 +89,7 @@ abstract class VideoView(
|
|
|
53
89
|
}
|
|
54
90
|
|
|
55
91
|
open fun dispose() {
|
|
92
|
+
checkVisibilityHandler.removeCallbacksAndMessages(null)
|
|
56
93
|
videoView.release()
|
|
57
94
|
}
|
|
58
95
|
|
|
@@ -74,5 +111,6 @@ abstract class VideoView(
|
|
|
74
111
|
|
|
75
112
|
fun setupTrack() {
|
|
76
113
|
videoView.setMirror((getVideoTrack() as? LocalVideoTrack)?.isFrontCamera() ?: false)
|
|
114
|
+
checkVisibilityHandler.post(checkVisibility)
|
|
77
115
|
}
|
|
78
116
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
package io.fishjam.reactnative.extensions
|
|
2
|
+
|
|
3
|
+
import com.fishjamcloud.client.media.CaptureDevice
|
|
4
|
+
|
|
5
|
+
typealias LocalCamera = Map<String, Any>
|
|
6
|
+
|
|
7
|
+
fun CaptureDevice.toLocalCamera(): LocalCamera =
|
|
8
|
+
mapOf<String, Any>(
|
|
9
|
+
"id" to deviceName,
|
|
10
|
+
"name" to deviceName,
|
|
11
|
+
"facingDirection" to
|
|
12
|
+
when (true) {
|
|
13
|
+
isFrontFacing -> "front"
|
|
14
|
+
isBackFacing -> "back"
|
|
15
|
+
else -> "unspecified"
|
|
16
|
+
}
|
|
17
|
+
)
|