@fishjam-cloud/react-native-client 0.4.1 → 0.6.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.
Files changed (127) hide show
  1. package/android/build.gradle +1 -1
  2. package/android/src/main/java/io/fishjam/reactnative/EmitableEvents.kt +104 -20
  3. package/android/src/main/java/io/fishjam/reactnative/RNFishjamClient.kt +83 -99
  4. package/android/src/main/java/io/fishjam/reactnative/RNFishjamClientModule.kt +21 -30
  5. package/android/src/main/java/io/fishjam/reactnative/VideoRendererViewModule.kt +6 -2
  6. package/android/src/main/java/io/fishjam/reactnative/VideoView.kt +41 -3
  7. package/android/src/main/java/io/fishjam/reactnative/extensions/CaptureDevice.kt +17 -0
  8. package/android/src/main/java/io/fishjam/reactnative/foregroundService/FishjamForegroundService.kt +10 -4
  9. package/android/src/main/java/io/fishjam/reactnative/foregroundService/ForegroundServiceManager.kt +41 -70
  10. package/android/src/main/java/io/fishjam/reactnative/foregroundService/ForegroundServiceState.kt +46 -0
  11. package/android/src/main/java/io/fishjam/reactnative/managers/ListenerManager.kt +22 -0
  12. package/android/src/main/java/io/fishjam/reactnative/managers/LocalCameraTracksChangedListenersManager.kt +2 -15
  13. package/android/src/main/java/io/fishjam/reactnative/managers/LocalTracksSwitchListenersManager.kt +1 -11
  14. package/android/src/main/java/io/fishjam/reactnative/managers/TracksUpdateListenersManager.kt +1 -15
  15. package/build/RNFishjamClientModule.d.ts +28 -12
  16. package/build/RNFishjamClientModule.d.ts.map +1 -1
  17. package/build/RNFishjamClientModule.js +19 -4
  18. package/build/RNFishjamClientModule.js.map +1 -1
  19. package/build/common/client.d.ts +0 -4
  20. package/build/common/client.d.ts.map +1 -1
  21. package/build/common/client.js +0 -4
  22. package/build/common/client.js.map +1 -1
  23. package/build/common/metadata.d.ts +1 -1
  24. package/build/common/metadata.js +1 -1
  25. package/build/common/metadata.js.map +1 -1
  26. package/build/common/webRTC.d.ts +2 -1
  27. package/build/common/webRTC.d.ts.map +1 -1
  28. package/build/common/webRTC.js.map +1 -1
  29. package/build/components/FishjamRoom/GridTrackItem.d.ts +11 -0
  30. package/build/components/FishjamRoom/GridTrackItem.d.ts.map +1 -0
  31. package/build/components/FishjamRoom/GridTrackItem.js +56 -0
  32. package/build/components/FishjamRoom/GridTrackItem.js.map +1 -0
  33. package/build/components/FishjamRoom/VideosGrid.d.ts +3 -0
  34. package/build/components/FishjamRoom/VideosGrid.d.ts.map +1 -0
  35. package/build/components/FishjamRoom/VideosGrid.js +20 -0
  36. package/build/components/FishjamRoom/VideosGrid.js.map +1 -0
  37. package/build/components/FishjamRoom/index.d.ts +6 -0
  38. package/build/components/FishjamRoom/index.d.ts.map +1 -0
  39. package/build/components/FishjamRoom/index.js +29 -0
  40. package/build/components/FishjamRoom/index.js.map +1 -0
  41. package/build/components/FishjamRoom/parsePeersToTracks.d.ts +4 -0
  42. package/build/components/FishjamRoom/parsePeersToTracks.d.ts.map +1 -0
  43. package/build/components/FishjamRoom/parsePeersToTracks.js +34 -0
  44. package/build/components/FishjamRoom/parsePeersToTracks.js.map +1 -0
  45. package/build/components/VideoRendererView.d.ts +6 -1
  46. package/build/components/VideoRendererView.d.ts.map +1 -1
  47. package/build/components/VideoRendererView.js.map +1 -1
  48. package/build/debug/stats/useRTCStatistics.d.ts.map +1 -1
  49. package/build/debug/stats/useRTCStatistics.js +13 -13
  50. package/build/debug/stats/useRTCStatistics.js.map +1 -1
  51. package/build/hooks/internal/useFishjamEvent.d.ts +3 -0
  52. package/build/hooks/internal/useFishjamEvent.d.ts.map +1 -0
  53. package/build/hooks/internal/useFishjamEvent.js +11 -0
  54. package/build/hooks/internal/useFishjamEvent.js.map +1 -0
  55. package/build/hooks/internal/useFishjamEventState.d.ts +3 -0
  56. package/build/hooks/internal/useFishjamEventState.d.ts.map +1 -0
  57. package/build/hooks/internal/useFishjamEventState.js +18 -0
  58. package/build/hooks/internal/useFishjamEventState.js.map +1 -0
  59. package/build/hooks/useAppScreenShare.d.ts.map +1 -1
  60. package/build/hooks/useAppScreenShare.js +6 -8
  61. package/build/hooks/useAppScreenShare.js.map +1 -1
  62. package/build/hooks/useAudioSettings.d.ts.map +1 -1
  63. package/build/hooks/useAudioSettings.js +8 -11
  64. package/build/hooks/useAudioSettings.js.map +1 -1
  65. package/build/hooks/useBandwidthEstimation.d.ts.map +1 -1
  66. package/build/hooks/useBandwidthEstimation.js +3 -4
  67. package/build/hooks/useBandwidthEstimation.js.map +1 -1
  68. package/build/hooks/useCamera.d.ts +6 -2
  69. package/build/hooks/useCamera.d.ts.map +1 -1
  70. package/build/hooks/useCamera.js +19 -23
  71. package/build/hooks/useCamera.js.map +1 -1
  72. package/build/hooks/useConnection.d.ts +42 -0
  73. package/build/hooks/useConnection.d.ts.map +1 -0
  74. package/build/hooks/useConnection.js +33 -0
  75. package/build/hooks/useConnection.js.map +1 -0
  76. package/build/hooks/useForegroundService.d.ts +12 -20
  77. package/build/hooks/useForegroundService.d.ts.map +1 -1
  78. package/build/hooks/useForegroundService.js +14 -4
  79. package/build/hooks/useForegroundService.js.map +1 -1
  80. package/build/hooks/useMicrophone.d.ts.map +1 -1
  81. package/build/hooks/useMicrophone.js +5 -11
  82. package/build/hooks/useMicrophone.js.map +1 -1
  83. package/build/hooks/usePeerStatus.d.ts +2 -3
  84. package/build/hooks/usePeerStatus.d.ts.map +1 -1
  85. package/build/hooks/usePeerStatus.js +4 -10
  86. package/build/hooks/usePeerStatus.js.map +1 -1
  87. package/build/hooks/usePeers.d.ts +50 -11
  88. package/build/hooks/usePeers.d.ts.map +1 -1
  89. package/build/hooks/usePeers.js +42 -18
  90. package/build/hooks/usePeers.js.map +1 -1
  91. package/build/hooks/useReconnection.d.ts +1 -1
  92. package/build/hooks/useReconnection.d.ts.map +1 -1
  93. package/build/hooks/useReconnection.js +4 -10
  94. package/build/hooks/useReconnection.js.map +1 -1
  95. package/build/hooks/useScreenShare.d.ts.map +1 -1
  96. package/build/hooks/useScreenShare.js +11 -16
  97. package/build/hooks/useScreenShare.js.map +1 -1
  98. package/build/hooks/useUpdatePeerMetadata.d.ts +15 -0
  99. package/build/hooks/useUpdatePeerMetadata.d.ts.map +1 -0
  100. package/build/hooks/useUpdatePeerMetadata.js +21 -0
  101. package/build/hooks/useUpdatePeerMetadata.js.map +1 -0
  102. package/build/index.d.ts +24 -16
  103. package/build/index.d.ts.map +1 -1
  104. package/build/index.js +18 -6
  105. package/build/index.js.map +1 -1
  106. package/build/types.d.ts +1 -1
  107. package/build/types.d.ts.map +1 -1
  108. package/build/types.js.map +1 -1
  109. package/build/utils/errorListener.d.ts.map +1 -1
  110. package/build/utils/errorListener.js +3 -4
  111. package/build/utils/errorListener.js.map +1 -1
  112. package/ios/Events.swift +94 -19
  113. package/ios/RNFishjamClient.podspec +1 -1
  114. package/ios/RNFishjamClient.swift +84 -114
  115. package/ios/RNFishjamClientModule.swift +14 -10
  116. package/ios/Utils.swift +0 -20
  117. package/ios/VideoPreviewView.swift +13 -13
  118. package/ios/VideoRendererView.swift +28 -25
  119. package/ios/VideoRendererViewModule.swift +8 -4
  120. package/ios/extensions/AVCaptureDevice.swift +20 -0
  121. package/package.json +11 -14
  122. package/plugin/build/withFishjamAndroid.js +18 -20
  123. package/plugin/build/withFishjamIos.js +99 -103
  124. package/build/hooks/useFishjamEvent.d.ts +0 -18
  125. package/build/hooks/useFishjamEvent.d.ts.map +0 -1
  126. package/build/hooks/useFishjamEvent.js +0 -27
  127. package/build/hooks/useFishjamEvent.js.map +0 -1
@@ -2,7 +2,7 @@ apply plugin: 'com.android.library'
2
2
  apply plugin: 'kotlin-android'
3
3
  apply plugin: 'maven-publish'
4
4
 
5
- def packageVersion = '0.4.1'
5
+ def packageVersion = '0.6.0'
6
6
 
7
7
  group = 'io.fishjam.reactnative'
8
8
  version = "${packageVersion}"
@@ -1,28 +1,112 @@
1
1
  package io.fishjam.reactnative
2
2
 
3
- @Suppress("ktlint:standard:enum-entry-name-case")
4
- enum class PeerStatus {
5
- connecting,
6
- connected,
7
- error,
8
- idle
3
+ import com.fishjamcloud.client.ReconnectionStatus
4
+ import com.fishjamcloud.client.models.SimulcastConfig
5
+ import com.twilio.audioswitch.AudioDevice
6
+ import io.fishjam.reactnative.extensions.LocalCamera
7
+
8
+ enum class PeerStatus(
9
+ val status: String
10
+ ) {
11
+ Connecting("connecting"),
12
+ Connected("connected"),
13
+ Idle("idle"),
14
+ Error("error")
9
15
  }
10
16
 
11
- enum class EmitableEvents {
12
- IsCameraOn,
13
- IsMicrophoneOn,
14
- IsScreenShareOn,
15
- SimulcastConfigUpdate,
16
- PeersUpdate,
17
- AudioDeviceUpdate,
18
- BandwidthEstimation,
19
- ReconnectionRetriesLimitReached,
20
- ReconnectionStarted,
21
- Reconnected,
22
- Warning,
23
- PeerStatusChanged;
17
+ class EmitableEvent private constructor(
18
+ private val event: EventName,
19
+ private val eventContent: Any? = null
20
+ ) {
21
+ enum class EventName {
22
+ IsMicrophoneOn,
23
+ IsScreenShareOn,
24
+ SimulcastConfigUpdate,
25
+ PeersUpdate,
26
+ AudioDeviceUpdate,
27
+ BandwidthEstimation,
28
+ Warning,
29
+ PeerStatusChanged,
30
+ ReconnectionStatusChanged,
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 allEvents = EmitableEvents.entries.map { it.name }.toTypedArray()
41
+ fun isMicrophoneOn(enabled: Boolean) = EmitableEvent(EventName.IsMicrophoneOn, enabled)
42
+
43
+ fun isScreenShareOn(enabled: Boolean) = EmitableEvent(EventName.IsScreenShareOn, enabled)
44
+
45
+ fun bandwidthEstimation(estimation: Long) = EmitableEvent(EventName.BandwidthEstimation, estimation.toFloat())
46
+
47
+ fun warning(message: String) = EmitableEvent(EventName.Warning, message)
48
+
49
+ fun peerStatusChanged(peerStatus: PeerStatus) = EmitableEvent(EventName.PeerStatusChanged, peerStatus.status)
50
+
51
+ fun reconnectionStatusChanged(reconnectionStatus: ReconnectionStatus) =
52
+ EmitableEvent(EventName.ReconnectionStatusChanged, reconnectionStatus.status)
53
+
54
+ fun currentCameraChanged(
55
+ localCamera: LocalCamera?,
56
+ isCameraOn: Boolean
57
+ ) = EmitableEvent(
58
+ EventName.CurrentCameraChanged,
59
+ mapOf(
60
+ "currentCamera" to localCamera,
61
+ "isCameraOn" to isCameraOn
62
+ )
63
+ )
64
+
65
+ fun simulcastConfigUpdate(simulcastConfig: SimulcastConfig) =
66
+ EmitableEvent(
67
+ EventName.SimulcastConfigUpdate,
68
+ mapOf(
69
+ "enabled" to simulcastConfig.enabled,
70
+ "activeEncodings" to simulcastConfig.activeEncodings.map { it.rid }
71
+ )
72
+ )
73
+
74
+ fun peersUpdate(peersData: List<Map<String, Any?>>) = EmitableEvent(EventName.PeersUpdate, peersData)
75
+
76
+ fun audioDeviceUpdate(
77
+ audioDevices: List<AudioDevice>,
78
+ selectedDevice: AudioDevice?
79
+ ): EmitableEvent {
80
+ val audioDeviceAsMap = { audioDevice: AudioDevice ->
81
+ mapOf(
82
+ "name" to audioDevice.name,
83
+ "type" to AudioDeviceKind.fromAudioDevice(audioDevice)?.typeName
84
+ )
85
+ }
86
+
87
+ return EmitableEvent(
88
+ EventName.AudioDeviceUpdate,
89
+ mapOf(
90
+ "selectedDevice" to (
91
+ if (selectedDevice != null) {
92
+ audioDeviceAsMap(
93
+ selectedDevice
94
+ )
95
+ } else {
96
+ null
97
+ }
98
+ ),
99
+ "availableDevices" to
100
+ audioDevices.map { audioDevice ->
101
+ audioDeviceAsMap(
102
+ audioDevice
103
+ )
104
+ }
105
+ )
106
+ )
107
+ }
108
+
109
+ val allEvents: Array<String>
110
+ get() = EventName.entries.map { it.name }.toTypedArray()
27
111
  }
28
112
  }
@@ -7,6 +7,9 @@ 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.ReconnectionStatus
11
+ import com.fishjamcloud.client.media.CaptureDevice
12
+ import com.fishjamcloud.client.media.CaptureDeviceChangedListener
10
13
  import com.fishjamcloud.client.media.LocalAudioTrack
11
14
  import com.fishjamcloud.client.media.LocalScreenShareTrack
12
15
  import com.fishjamcloud.client.media.LocalVideoTrack
@@ -27,6 +30,8 @@ import com.twilio.audioswitch.AudioDevice
27
30
  import expo.modules.kotlin.AppContext
28
31
  import expo.modules.kotlin.Promise
29
32
  import expo.modules.kotlin.exception.CodedException
33
+ import fishjam.media_events.server.Server
34
+ import io.fishjam.reactnative.extensions.toLocalCamera
30
35
  import io.fishjam.reactnative.foregroundService.ForegroundServiceManager
31
36
  import io.fishjam.reactnative.managers.LocalCameraTracksChangedListenersManager
32
37
  import io.fishjam.reactnative.managers.LocalTracksSwitchListenersManager
@@ -40,7 +45,8 @@ import org.webrtc.Logging
40
45
 
41
46
  class RNFishjamClient(
42
47
  val sendEvent: (name: String, data: Map<String, Any?>) -> Unit
43
- ) : FishjamClientListener {
48
+ ) : FishjamClientListener,
49
+ CaptureDeviceChangedListener {
44
50
  private val SCREENSHARE_REQUEST = 1
45
51
 
46
52
  var isMicrophoneOn = false
@@ -68,14 +74,21 @@ class RNFishjamClient(
68
74
 
69
75
  var appContext: AppContext? = null
70
76
 
71
- var peerStatus = PeerStatus.idle
77
+ var peerStatus = PeerStatus.Idle
72
78
  private set(value) {
73
79
  field = value
74
- val event = EmitableEvents.PeerStatusChanged
75
- emitEvent(event, mapOf(event.name to value))
80
+ emitEvent(EmitableEvent.peerStatusChanged(value))
76
81
  }
77
82
 
78
- private var foregroundServiceManager: ForegroundServiceManager? = null
83
+ var reconnectionStatus = ReconnectionStatus.Idle
84
+ private set(value) {
85
+ field = value
86
+ emitEvent(EmitableEvent.reconnectionStatusChanged(value))
87
+ }
88
+
89
+ private val foregroundServiceManager by lazy {
90
+ ForegroundServiceManager(appContext ?: throw CodedException("appContext not found"))
91
+ }
79
92
 
80
93
  companion object {
81
94
  val trackUpdateListenersManager = TracksUpdateListenersManager()
@@ -236,7 +249,7 @@ class RNFishjamClient(
236
249
  CoroutineScope(Dispatchers.Main).launch {
237
250
  connectPromise?.reject(ConnectionError(reason))
238
251
  connectPromise = null
239
- peerStatus = PeerStatus.error
252
+ peerStatus = PeerStatus.Error
240
253
  }
241
254
  }
242
255
 
@@ -247,14 +260,14 @@ class RNFishjamClient(
247
260
  config: ConnectConfig,
248
261
  promise: Promise
249
262
  ) {
250
- peerStatus = PeerStatus.connecting
263
+ peerStatus = PeerStatus.Connecting
251
264
  connectPromise = promise
252
265
  localUserMetadata = mapOf("server" to emptyMap(), "peer" to peerMetadata)
253
266
  fishjamClient.connect(
254
267
  com.fishjamcloud.client.ConnectConfig(
255
268
  url,
256
269
  peerToken,
257
- localUserMetadata,
270
+ peerMetadata,
258
271
  ReconnectConfig(
259
272
  config.reconnectConfig.maxAttempts,
260
273
  config.reconnectConfig.initialDelayMs,
@@ -278,20 +291,22 @@ class RNFishjamClient(
278
291
  }
279
292
  }
280
293
 
281
- suspend fun startCamera(config: CameraConfig) {
294
+ suspend fun startCamera(config: CameraConfig): Boolean {
282
295
  if (isCameraInitialized) {
283
- emitWarning("Camera already started. You may only call startCamera once before leaveRoom is called.")
284
- return
296
+ emitEvent(EmitableEvent.warning("Camera already started. You may only call startCamera once before leaveRoom is called."))
297
+ return true
285
298
  }
286
299
  if (!PermissionUtils.requestCameraPermission(appContext)) {
287
- emitWarning("Camera permission not granted.")
288
- return
300
+ emitEvent(EmitableEvent.warning("Camera permission not granted."))
301
+ return false
289
302
  }
290
303
 
291
304
  val cameraTrack = createCameraTrack(config)
305
+ cameraTrack.captureDeviceChangedListener = this
292
306
  setCameraTrackState(cameraTrack, config.cameraEnabled)
293
307
  emitEndpoints()
294
308
  isCameraInitialized = true
309
+ return true
295
310
  }
296
311
 
297
312
  private suspend fun createCameraTrack(config: CameraConfig): LocalVideoTrack {
@@ -310,8 +325,7 @@ class RNFishjamClient(
310
325
  ) {
311
326
  cameraTrack.setEnabled(isEnabled)
312
327
  isCameraOn = isEnabled
313
- val event = EmitableEvents.IsCameraOn
314
- emitEvent(event, mapOf(event.name to isEnabled))
328
+ emitEvent(EmitableEvent.currentCameraChanged(cameraTrack.getCaptureDevice()?.toLocalCamera(), isEnabled))
315
329
  localCameraTracksChangedListenersManager.notifyListeners()
316
330
  }
317
331
 
@@ -337,7 +351,7 @@ class RNFishjamClient(
337
351
 
338
352
  private suspend fun startMicrophone() {
339
353
  if (!PermissionUtils.requestMicrophonePermission(appContext)) {
340
- emitWarning("Microphone permission not granted.")
354
+ emitEvent(EmitableEvent.warning("Microphone permission not granted."))
341
355
  return
342
356
  }
343
357
 
@@ -352,8 +366,7 @@ class RNFishjamClient(
352
366
  ) {
353
367
  microphoneTrack.setEnabled(isEnabled)
354
368
  isMicrophoneOn = isEnabled
355
- val event = EmitableEvents.IsMicrophoneOn
356
- emitEvent(event, mapOf(event.name to isEnabled))
369
+ emitEvent(EmitableEvent.isMicrophoneOn(isEnabled))
357
370
  }
358
371
 
359
372
  suspend fun toggleMicrophone(): Boolean {
@@ -362,6 +375,15 @@ class RNFishjamClient(
362
375
  } else {
363
376
  getLocalAudioTrack()?.let { setMicrophoneTrackState(it, !isMicrophoneOn) }
364
377
  }
378
+
379
+ updateLocalAudioTrackMetadata(
380
+ mapOf(
381
+ "active" to isMicrophoneOn,
382
+ "paused" to !isMicrophoneOn, // TODO: FCE-711,
383
+ "type" to "microphone"
384
+ )
385
+ )
386
+
365
387
  return isMicrophoneOn
366
388
  }
367
389
 
@@ -380,22 +402,13 @@ class RNFishjamClient(
380
402
  }
381
403
  }
382
404
 
383
- fun configureForegroundService(config: ForegroundServiceNotificationConfig) {
384
- if (foregroundServiceManager == null) {
385
- foregroundServiceManager = ForegroundServiceManager(appContext!!, config)
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)
405
+ suspend fun startForegroundService(config: ForegroundServiceConfig) {
406
+ foregroundServiceManager.updateServiceWithConfig(config)
407
+ foregroundServiceManager.start()
395
408
  }
396
409
 
397
410
  fun stopForegroundService() {
398
- foregroundServiceManager?.stopForegroundService()
411
+ foregroundServiceManager.stop()
399
412
  }
400
413
 
401
414
  suspend fun toggleScreenShare(screenShareOptions: ScreenShareOptions) {
@@ -408,6 +421,7 @@ class RNFishjamClient(
408
421
  screenShareOptions.maxBandwidthMap,
409
422
  screenShareOptions.maxBandwidthInt
410
423
  )
424
+
411
425
  if (!isScreenShareOn) {
412
426
  ensureConnected()
413
427
  startScreenShare()
@@ -421,7 +435,6 @@ class RNFishjamClient(
421
435
  mapOf(
422
436
  "id" to endpoint.id,
423
437
  "isLocal" to (endpoint.id == fishjamClient.getLocalEndpoint().id),
424
- "type" to endpoint.type,
425
438
  "metadata" to endpoint.metadata,
426
439
  "tracks" to
427
440
  endpoint.tracks.values.mapNotNull { track ->
@@ -440,7 +453,11 @@ class RNFishjamClient(
440
453
  "id" to track.id(),
441
454
  "type" to "Audio",
442
455
  "metadata" to track.metadata,
443
- "vadStatus" to track.vadStatus.value
456
+ "vadStatus" to
457
+ when (track.vadStatus) {
458
+ Server.MediaEvent.VadNotification.Status.STATUS_SPEECH -> "speech"
459
+ else -> "silence"
460
+ }
444
461
  )
445
462
 
446
463
  is LocalVideoTrack ->
@@ -475,19 +492,12 @@ class RNFishjamClient(
475
492
  fun getCaptureDevices(): List<Map<String, Any>> {
476
493
  val devices = LocalVideoTrack.getCaptureDevices(appContext?.reactContext!!)
477
494
  return devices.map { device ->
478
- mapOf<String, Any>(
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
- )
495
+ device.toLocalCamera()
488
496
  }
489
497
  }
490
498
 
499
+ fun getCurrentCaptureDevice(): Map<String, Any>? = getLocalVideoTrack()?.getCaptureDevice()?.toLocalCamera()
500
+
491
501
  fun updatePeerMetadata(metadata: Metadata) {
492
502
  ensureConnected()
493
503
  fishjamClient.updatePeerMetadata(metadata)
@@ -508,7 +518,7 @@ class RNFishjamClient(
508
518
  }
509
519
  }
510
520
 
511
- fun updateLocalAudioTrackMetadata(metadata: Metadata) {
521
+ private fun updateLocalAudioTrackMetadata(metadata: Metadata) {
512
522
  ensureAudioTrack()
513
523
  getLocalAudioTrack()?.let {
514
524
  updateTrackMetadata(it.id(), metadata)
@@ -606,13 +616,15 @@ class RNFishjamClient(
606
616
  fishjamClient.setTargetTrackEncoding(trackId, encoding.toTrackEncoding())
607
617
  }
608
618
 
609
- fun toggleVideoTrackEncoding(encoding: String): Map<String, Any> {
619
+ fun toggleVideoTrackEncoding(encoding: String): Map<String, Any?> {
610
620
  ensureVideoTrack()
611
621
  val trackId = getLocalVideoTrack()?.id() ?: return emptyMap()
612
622
  videoSimulcastConfig = toggleTrackEncoding(encoding, trackId, videoSimulcastConfig)
613
- val eventName = EmitableEvents.SimulcastConfigUpdate
614
- emitEvent(eventName, getSimulcastConfigAsRNMap(videoSimulcastConfig))
615
- return getSimulcastConfigAsRNMap(videoSimulcastConfig)
623
+
624
+ val event = EmitableEvent.simulcastConfigUpdate(videoSimulcastConfig)
625
+ emitEvent(event)
626
+
627
+ return event.data
616
628
  }
617
629
 
618
630
  fun setVideoTrackEncodingBandwidth(
@@ -712,6 +724,10 @@ class RNFishjamClient(
712
724
  if (mediaProjectionIntent == null) {
713
725
  throw MissingScreenSharePermission()
714
726
  }
727
+
728
+ foregroundServiceManager.updateService { screenSharingEnabled = true }
729
+ foregroundServiceManager.start()
730
+
715
731
  fishjamClient.createScreenShareTrack(
716
732
  mediaProjectionIntent!!,
717
733
  videoParameters,
@@ -743,13 +759,14 @@ class RNFishjamClient(
743
759
 
744
760
  private fun setScreenShareTrackState(isEnabled: Boolean) {
745
761
  isScreenShareOn = isEnabled
746
- val event = EmitableEvents.IsScreenShareOn
747
- emitEvent(event, mapOf(event.name to isEnabled))
762
+ emitEvent(EmitableEvent.isScreenShareOn(isEnabled))
748
763
  }
749
764
 
750
765
  private fun stopScreenShare() {
751
766
  ensureScreenShareTrack()
752
767
  coroutineScope.launch {
768
+ foregroundServiceManager.updateService { screenSharingEnabled = false }
769
+ foregroundServiceManager.start()
753
770
  val screenShareTrack =
754
771
  fishjamClient.getLocalEndpoint().tracks.values.first { track ->
755
772
  track is LocalScreenShareTrack
@@ -762,58 +779,21 @@ class RNFishjamClient(
762
779
  }
763
780
  }
764
781
 
765
- private fun emitEvent(
766
- event: EmitableEvents,
767
- data: Map<String, Any?> = mapOf()
768
- ) {
782
+ private fun emitEvent(event: EmitableEvent) {
769
783
  CoroutineScope(Dispatchers.Main).launch {
770
- sendEvent(event.name, data)
784
+ sendEvent(event.name, event.data)
771
785
  }
772
786
  }
773
787
 
774
- fun emitWarning(warning: String) {
775
- emitEvent(EmitableEvents.Warning, mapOf("message" to warning))
776
- }
777
-
778
788
  private fun emitEndpoints() {
779
- val event = EmitableEvents.PeersUpdate
780
- emitEvent(event, mapOf(event.name to getPeers()))
789
+ emitEvent(EmitableEvent.peersUpdate(getPeers()))
781
790
  }
782
791
 
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
792
  private fun emitAudioDeviceEvent(
790
793
  audioDevices: List<AudioDevice>,
791
794
  selectedDevice: AudioDevice?
792
795
  ) {
793
- val event = EmitableEvents.AudioDeviceUpdate
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
- )
796
+ emitEvent(EmitableEvent.audioDeviceUpdate(audioDevices, selectedDevice))
817
797
  }
818
798
 
819
799
  private fun getSimulcastConfigAsRNMap(simulcastConfig: SimulcastConfig): Map<String, Any> =
@@ -834,7 +814,7 @@ class RNFishjamClient(
834
814
  connectPromise?.resolve(null)
835
815
  connectPromise = null
836
816
  emitEndpoints()
837
- peerStatus = PeerStatus.connected
817
+ peerStatus = PeerStatus.Connected
838
818
  }
839
819
  }
840
820
 
@@ -885,12 +865,11 @@ class RNFishjamClient(
885
865
  override fun onPeerUpdated(peer: Peer) {}
886
866
 
887
867
  override fun onBandwidthEstimationChanged(estimation: Long) {
888
- val event = EmitableEvents.BandwidthEstimation
889
- emitEvent(event, mapOf(event.name to estimation.toFloat()))
868
+ emitEvent(EmitableEvent.bandwidthEstimation(estimation))
890
869
  }
891
870
 
892
871
  override fun onDisconnected() {
893
- peerStatus = PeerStatus.idle
872
+ peerStatus = PeerStatus.Idle
894
873
  }
895
874
 
896
875
  override fun onSocketClose(
@@ -900,7 +879,7 @@ class RNFishjamClient(
900
879
  CoroutineScope(Dispatchers.Main).launch {
901
880
  connectPromise?.reject(SocketClosedError(code, reason))
902
881
  connectPromise = null
903
- peerStatus = PeerStatus.error
882
+ peerStatus = PeerStatus.Idle
904
883
  }
905
884
  }
906
885
 
@@ -908,18 +887,23 @@ class RNFishjamClient(
908
887
  CoroutineScope(Dispatchers.Main).launch {
909
888
  connectPromise?.reject(SocketError(t.message ?: t.toString()))
910
889
  connectPromise = null
890
+ peerStatus = PeerStatus.Error
911
891
  }
912
892
  }
913
893
 
914
894
  override fun onReconnected() {
915
- emitEvent(EmitableEvents.Reconnected)
895
+ reconnectionStatus = ReconnectionStatus.Reconnecting
916
896
  }
917
897
 
918
898
  override fun onReconnectionStarted() {
919
- emitEvent(EmitableEvents.ReconnectionStarted)
899
+ reconnectionStatus = ReconnectionStatus.Idle
920
900
  }
921
901
 
922
902
  override fun onReconnectionRetriesLimitReached() {
923
- emitEvent(EmitableEvents.ReconnectionRetriesLimitReached)
903
+ reconnectionStatus = ReconnectionStatus.Error
904
+ }
905
+
906
+ override fun onCaptureDeviceChanged(captureDevice: CaptureDevice?) {
907
+ emitEvent(EmitableEvent.currentCameraChanged(captureDevice?.toLocalCamera(), isCameraOn))
924
908
  }
925
909
  }
@@ -81,7 +81,7 @@ class ConnectConfig : Record {
81
81
  val reconnectConfig: ReconnectConfig = ReconnectConfig()
82
82
  }
83
83
 
84
- class ForegroundServiceNotificationConfig : Record {
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 enableMicrophone: Boolean = false
98
+ val enableCamera: Boolean? = null
104
99
 
105
100
  @Field
106
- val enableScreenSharing: Boolean = false
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(EmitableEvents.allEvents)
116
+ Events(EmitableEvent.allEvents)
122
117
 
123
118
  OnCreate {
124
119
  rnFishjamClient.onModuleCreate(appContext)
@@ -148,12 +143,24 @@ 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
  }
154
153
 
155
154
  Property("peerStatus") {
156
- return@Property rnFishjamClient.peerStatus
155
+ return@Property rnFishjamClient.peerStatus.status
156
+ }
157
+
158
+ Property("reconnectionStatus") {
159
+ return@Property rnFishjamClient.reconnectionStatus.status
160
+ }
161
+
162
+ Function("getPeers") {
163
+ return@Function rnFishjamClient.getPeers()
157
164
  }
158
165
 
159
166
  AsyncFunction(
@@ -171,8 +178,8 @@ class RNFishjamClientModule : Module() {
171
178
  }
172
179
 
173
180
  AsyncFunction("startCamera") Coroutine { config: CameraConfig ->
174
- withContext(Dispatchers.Main) {
175
- rnFishjamClient.startCamera(config)
181
+ return@Coroutine withContext(Dispatchers.Main) {
182
+ return@withContext rnFishjamClient.startCamera(config)
176
183
  }
177
184
  }
178
185
 
@@ -216,12 +223,6 @@ class RNFishjamClientModule : Module() {
216
223
  }
217
224
  }
218
225
 
219
- AsyncFunction("getPeers") Coroutine { ->
220
- withContext(Dispatchers.Main) {
221
- rnFishjamClient.getPeers()
222
- }
223
- }
224
-
225
226
  AsyncFunction("updatePeerMetadata") Coroutine { metadata: Map<String, Any> ->
226
227
  withContext(Dispatchers.Main) {
227
228
  rnFishjamClient.updatePeerMetadata(metadata)
@@ -234,12 +235,6 @@ class RNFishjamClientModule : Module() {
234
235
  }
235
236
  }
236
237
 
237
- AsyncFunction("updateAudioTrackMetadata") Coroutine { metadata: Map<String, Any> ->
238
- withContext(Dispatchers.Main) {
239
- rnFishjamClient.updateLocalAudioTrackMetadata(metadata)
240
- }
241
- }
242
-
243
238
  AsyncFunction("updateScreenShareTrackMetadata") Coroutine { metadata: Map<String, Any> ->
244
239
  withContext(Dispatchers.Main) {
245
240
  rnFishjamClient.updateLocalScreenShareTrackMetadata(metadata)
@@ -301,18 +296,14 @@ class RNFishjamClientModule : Module() {
301
296
  }
302
297
 
303
298
  AsyncFunction("changeWebRTCLoggingSeverity") Coroutine { severity: String ->
304
- CoroutineScope(Dispatchers.Main).launch {
299
+ withContext(Dispatchers.Main) {
305
300
  rnFishjamClient.changeWebRTCLoggingSeverity(severity)
306
301
  }
307
302
  }
308
303
 
309
304
  AsyncFunction("getStatistics") { rnFishjamClient.getStatistics() }
310
305
 
311
- Function("configureForegroundService") { config: ForegroundServiceNotificationConfig ->
312
- return@Function rnFishjamClient.configureForegroundService(config)
313
- }
314
-
315
- AsyncFunction("startForegroundService") Coroutine { config: ForegroundServicePermissionsConfig ->
306
+ AsyncFunction("startForegroundService") Coroutine { config: ForegroundServiceConfig ->
316
307
  rnFishjamClient.startForegroundService(config)
317
308
  }
318
309
 
@@ -15,13 +15,17 @@ class VideoRendererViewModule : Module() {
15
15
  RNFishjamClient.localTracksSwitchListenerManager.remove(view)
16
16
  }
17
17
 
18
- Prop("trackId") { view: VideoRendererView, trackId: String ->
18
+ Prop("trackId") { view, trackId: String ->
19
19
  view.init(trackId)
20
20
  }
21
21
 
22
- Prop("videoLayout") { view: VideoRendererView, videoLayout: String ->
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
  }