@fishjam-cloud/react-native-client 0.1.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 (138) hide show
  1. package/.eslintignore +7 -0
  2. package/.eslintrc +6 -0
  3. package/.prettierrc +9 -0
  4. package/.watchmanconfig +1 -0
  5. package/android/.editorconfig +9 -0
  6. package/android/build.gradle +89 -0
  7. package/android/src/main/AndroidManifest.xml +2 -0
  8. package/android/src/main/java/org/membraneframework/reactnative/AudioDeviceKind.kt +34 -0
  9. package/android/src/main/java/org/membraneframework/reactnative/AudioSwitchManager.kt +61 -0
  10. package/android/src/main/java/org/membraneframework/reactnative/EmitableEvents.kt +14 -0
  11. package/android/src/main/java/org/membraneframework/reactnative/Errors.kt +31 -0
  12. package/android/src/main/java/org/membraneframework/reactnative/RNFishjamClient.kt +866 -0
  13. package/android/src/main/java/org/membraneframework/reactnative/RNFishjamClientModule.kt +294 -0
  14. package/android/src/main/java/org/membraneframework/reactnative/Utils.kt +11 -0
  15. package/android/src/main/java/org/membraneframework/reactnative/VideoPreviewView.kt +40 -0
  16. package/android/src/main/java/org/membraneframework/reactnative/VideoPreviewViewModule.kt +17 -0
  17. package/android/src/main/java/org/membraneframework/reactnative/VideoRendererView.kt +58 -0
  18. package/android/src/main/java/org/membraneframework/reactnative/VideoRendererViewModule.kt +25 -0
  19. package/android/src/main/java/org/membraneframework/reactnative/VideoView.kt +77 -0
  20. package/app.plugin.js +1 -0
  21. package/babel.config.js +2 -0
  22. package/build/RNFishjamClientModule.d.ts +47 -0
  23. package/build/RNFishjamClientModule.d.ts.map +1 -0
  24. package/build/RNFishjamClientModule.js +4 -0
  25. package/build/RNFishjamClientModule.js.map +1 -0
  26. package/build/common/client.d.ts +19 -0
  27. package/build/common/client.d.ts.map +1 -0
  28. package/build/common/client.js +8 -0
  29. package/build/common/client.js.map +1 -0
  30. package/build/common/eventEmitter.d.ts +16 -0
  31. package/build/common/eventEmitter.d.ts.map +1 -0
  32. package/build/common/eventEmitter.js +17 -0
  33. package/build/common/eventEmitter.js.map +1 -0
  34. package/build/common/metadata.d.ts +7 -0
  35. package/build/common/metadata.d.ts.map +1 -0
  36. package/build/common/metadata.js +9 -0
  37. package/build/common/metadata.js.map +1 -0
  38. package/build/common/webRTC.d.ts +19 -0
  39. package/build/common/webRTC.d.ts.map +1 -0
  40. package/build/common/webRTC.js +22 -0
  41. package/build/common/webRTC.js.map +1 -0
  42. package/build/components/VideoPreviewView.d.ts +21 -0
  43. package/build/components/VideoPreviewView.d.ts.map +1 -0
  44. package/build/components/VideoPreviewView.js +7 -0
  45. package/build/components/VideoPreviewView.js.map +1 -0
  46. package/build/components/VideoRendererView.d.ts +19 -0
  47. package/build/components/VideoRendererView.d.ts.map +1 -0
  48. package/build/components/VideoRendererView.js +7 -0
  49. package/build/components/VideoRendererView.js.map +1 -0
  50. package/build/hooks/useAudioSettings.d.ts +23 -0
  51. package/build/hooks/useAudioSettings.d.ts.map +1 -0
  52. package/build/hooks/useAudioSettings.js +72 -0
  53. package/build/hooks/useAudioSettings.js.map +1 -0
  54. package/build/hooks/useBandwidthEstimation.d.ts +12 -0
  55. package/build/hooks/useBandwidthEstimation.d.ts.map +1 -0
  56. package/build/hooks/useBandwidthEstimation.js +16 -0
  57. package/build/hooks/useBandwidthEstimation.js.map +1 -0
  58. package/build/hooks/useCamera.d.ts +80 -0
  59. package/build/hooks/useCamera.d.ts.map +1 -0
  60. package/build/hooks/useCamera.js +140 -0
  61. package/build/hooks/useCamera.js.map +1 -0
  62. package/build/hooks/useMicrophone.d.ts +8 -0
  63. package/build/hooks/useMicrophone.d.ts.map +1 -0
  64. package/build/hooks/useMicrophone.js +27 -0
  65. package/build/hooks/useMicrophone.js.map +1 -0
  66. package/build/hooks/useParticipants.d.ts +62 -0
  67. package/build/hooks/useParticipants.d.ts.map +1 -0
  68. package/build/hooks/useParticipants.js +32 -0
  69. package/build/hooks/useParticipants.js.map +1 -0
  70. package/build/hooks/useReconnection.d.ts +5 -0
  71. package/build/hooks/useReconnection.d.ts.map +1 -0
  72. package/build/hooks/useReconnection.js +23 -0
  73. package/build/hooks/useReconnection.js.map +1 -0
  74. package/build/hooks/useScreencast.d.ts +38 -0
  75. package/build/hooks/useScreencast.d.ts.map +1 -0
  76. package/build/hooks/useScreencast.js +81 -0
  77. package/build/hooks/useScreencast.js.map +1 -0
  78. package/build/index.d.ts +24 -0
  79. package/build/index.d.ts.map +1 -0
  80. package/build/index.js +14 -0
  81. package/build/index.js.map +1 -0
  82. package/build/protos/fishjam/peer_notifications.d.ts +63 -0
  83. package/build/protos/fishjam/peer_notifications.d.ts.map +1 -0
  84. package/build/protos/fishjam/peer_notifications.js +235 -0
  85. package/build/protos/fishjam/peer_notifications.js.map +1 -0
  86. package/build/stats/types.d.ts +55 -0
  87. package/build/stats/types.d.ts.map +1 -0
  88. package/build/stats/types.js +2 -0
  89. package/build/stats/types.js.map +1 -0
  90. package/build/stats/useRTCStatistics.d.ts +8 -0
  91. package/build/stats/useRTCStatistics.d.ts.map +1 -0
  92. package/build/stats/useRTCStatistics.js +78 -0
  93. package/build/stats/useRTCStatistics.js.map +1 -0
  94. package/build/types.d.ts +43 -0
  95. package/build/types.d.ts.map +1 -0
  96. package/build/types.js +2 -0
  97. package/build/types.js.map +1 -0
  98. package/expo-module.config.json +17 -0
  99. package/ios/Events.swift +13 -0
  100. package/ios/RNFishjamClient.podspec +30 -0
  101. package/ios/RNFishjamClient.swift +836 -0
  102. package/ios/RNFishjamClientModule.swift +220 -0
  103. package/ios/Utils.swift +43 -0
  104. package/ios/VideoPreviewView.swift +64 -0
  105. package/ios/VideoPreviewViewModule.swift +21 -0
  106. package/ios/VideoRendererView.swift +84 -0
  107. package/ios/VideoRendererViewModule.swift +17 -0
  108. package/ios/swift-format-config.json +56 -0
  109. package/package.json +89 -0
  110. package/plugin/broadcastExtensionFiles/Info.plist +27 -0
  111. package/plugin/broadcastExtensionFiles/MembraneBroadcastSampleHandler.swift +50 -0
  112. package/plugin/broadcastExtensionFiles/MembraneScreenBroadcastExtension.entitlements +10 -0
  113. package/plugin/src/withMembrane.ts +310 -0
  114. package/plugin/tsconfig.json +9 -0
  115. package/scripts/lint.sh +18 -0
  116. package/scripts/lint_check.sh +14 -0
  117. package/src/RNFishjamClientModule.ts +73 -0
  118. package/src/__tests__/index.test.tsx +199 -0
  119. package/src/common/client.ts +33 -0
  120. package/src/common/eventEmitter.ts +21 -0
  121. package/src/common/metadata.ts +12 -0
  122. package/src/common/webRTC.ts +31 -0
  123. package/src/components/VideoPreviewView.tsx +33 -0
  124. package/src/components/VideoRendererView.tsx +31 -0
  125. package/src/hooks/useAudioSettings.ts +115 -0
  126. package/src/hooks/useBandwidthEstimation.ts +24 -0
  127. package/src/hooks/useCamera.ts +270 -0
  128. package/src/hooks/useMicrophone.ts +38 -0
  129. package/src/hooks/useParticipants.ts +118 -0
  130. package/src/hooks/useReconnection.ts +41 -0
  131. package/src/hooks/useScreencast.ts +146 -0
  132. package/src/index.tsx +63 -0
  133. package/src/protos/fishjam/peer_notifications.ts +299 -0
  134. package/src/stats/types.ts +56 -0
  135. package/src/stats/useRTCStatistics.ts +97 -0
  136. package/src/types.ts +49 -0
  137. package/tsconfig.json +9 -0
  138. package/typedoc.json +5 -0
@@ -0,0 +1,220 @@
1
+ import ExpoModulesCore
2
+
3
+ struct RNSimulcastConfig: Record {
4
+ @Field
5
+ var enabled: Bool = false
6
+
7
+ @Field
8
+ var activeEncodings: [String] = []
9
+ }
10
+
11
+ struct CameraConfig: Record {
12
+ @Field
13
+ var quality: String = "VGA169"
14
+
15
+ @Field
16
+ var flipVideo: Bool = false
17
+
18
+ @Field
19
+ var videoTrackMetadata: [String: Any] = [:]
20
+
21
+ @Field
22
+ var simulcastConfig: RNSimulcastConfig = RNSimulcastConfig()
23
+
24
+ @Field
25
+ var maxBandwidth: RNTrackBandwidthLimit = RNTrackBandwidthLimit(0)
26
+
27
+ @Field
28
+ var cameraEnabled: Bool = true
29
+
30
+ @Field
31
+ var captureDeviceId: String? = nil
32
+ }
33
+
34
+ struct MicrophoneConfig: Record {
35
+ @Field
36
+ var audioTrackMetadata: [String: Any] = [:]
37
+
38
+ @Field
39
+ var microphoneEnabled: Bool = true
40
+ }
41
+
42
+ struct ScreencastOptions: Record {
43
+ @Field
44
+ var quality: String = "HD15"
45
+
46
+ @Field
47
+ var screencastMetadata: [String: Any] = [:]
48
+
49
+ @Field
50
+ var simulcastConfig: RNSimulcastConfig = RNSimulcastConfig()
51
+
52
+ @Field
53
+ var maxBandwidth: RNTrackBandwidthLimit = RNTrackBandwidthLimit(0)
54
+ }
55
+
56
+ struct ReconnectConfig: Record {
57
+ @Field
58
+ var maxAttempts: Int = 5
59
+
60
+ @Field
61
+ var initialDelayMs: Int = 1000
62
+
63
+ @Field
64
+ var delayMs: Int = 1000
65
+ }
66
+
67
+ struct ConnectConfig: Record {
68
+ @Field
69
+ var reconnectConfig: ReconnectConfig = ReconnectConfig()
70
+ }
71
+
72
+ typealias RNTrackBandwidthLimit = Either<Int, [String: Int]>
73
+
74
+ public class RNFishjamClientModule: Module {
75
+ public func definition() -> ModuleDefinition {
76
+ Name("RNFishjamClient")
77
+
78
+ Events(
79
+ "IsCameraOn",
80
+ "IsMicrophoneOn",
81
+ "IsScreencastOn",
82
+ "SimulcastConfigUpdate",
83
+ "PeersUpdate",
84
+ "AudioDeviceUpdate",
85
+ "SendMediaEvent",
86
+ "BandwidthEstimation",
87
+ "ReconnectionRetriesLimitReached",
88
+ "ReconnectionStarted",
89
+ "Reconnected")
90
+
91
+ let rnFishjamClient: RNFishjamClient = {
92
+ let client = RNFishjamClient {
93
+ (eventName: String, data: [String: Any]) in
94
+ self.sendEvent(eventName, data)
95
+ }
96
+ client.create()
97
+ return client
98
+ }()
99
+
100
+ AsyncFunction("connect") {
101
+ (url: String, peerToken: String, peerMetadata: [String: Any], config: ConnectConfig, promise: Promise) in
102
+ rnFishjamClient.connect(
103
+ url: url, peerToken: peerToken, peerMetadata: peerMetadata, config: config, promise: promise)
104
+ }
105
+
106
+ AsyncFunction("leaveRoom") {
107
+ rnFishjamClient.leaveRoom()
108
+ }
109
+
110
+ AsyncFunction("startCamera") { (config: CameraConfig) in
111
+ try rnFishjamClient.startCamera(config: config)
112
+ }
113
+
114
+ Property("isMicrophoneOn") {
115
+ return rnFishjamClient.isMicrophoneOn
116
+ }
117
+
118
+ AsyncFunction("toggleMicrophone") {
119
+ try rnFishjamClient.toggleMicrophone()
120
+ }
121
+
122
+ Property("isCameraOn") {
123
+ return rnFishjamClient.isCameraOn
124
+ }
125
+
126
+ AsyncFunction("toggleCamera") {
127
+ try rnFishjamClient.toggleCamera()
128
+ }
129
+
130
+ AsyncFunction("flipCamera") {
131
+ try rnFishjamClient.flipCamera()
132
+ }
133
+
134
+ AsyncFunction("switchCamera") { (captureDeviceId: String) in
135
+ try rnFishjamClient.switchCamera(captureDeviceId: captureDeviceId)
136
+ }
137
+
138
+ AsyncFunction("getCaptureDevices") {
139
+ rnFishjamClient.getCaptureDevices()
140
+ }
141
+
142
+ AsyncFunction("toggleScreencast") { (screencastOptions: ScreencastOptions) in
143
+ try rnFishjamClient.toggleScreencast(screencastOptions: screencastOptions)
144
+ }
145
+
146
+ Property("isScreencastOn") {
147
+ return rnFishjamClient.isScreencastOn
148
+ }
149
+
150
+ AsyncFunction("getPeers") {
151
+ try rnFishjamClient.getPeers()
152
+ }
153
+
154
+ AsyncFunction("updatePeerMetadata") { (metadata: [String: Any]) in
155
+ try rnFishjamClient.updatePeerMetadata(metadata: metadata)
156
+ }
157
+
158
+ AsyncFunction("updateVideoTrackMetadata") { (metadata: [String: Any]) in
159
+ try rnFishjamClient.updateLocalVideoTrackMetadata(metadata: metadata)
160
+ }
161
+
162
+ AsyncFunction("updateAudioTrackMetadata") { (metadata: [String: Any]) in
163
+ try rnFishjamClient.updateLocalAudioTrackMetadata(metadata: metadata)
164
+ }
165
+
166
+ AsyncFunction("updateScreencastTrackMetadata") { (metadata: [String: Any]) in
167
+ try rnFishjamClient.updateLocalScreencastTrackMetadata(metadata: metadata)
168
+ }
169
+
170
+ AsyncFunction("toggleScreencastTrackEncoding") { (encoding: String) in
171
+ try rnFishjamClient.toggleScreencastTrackEncoding(encoding: encoding)
172
+ }
173
+
174
+ AsyncFunction("setScreencastTrackBandwidth") { (bandwidth: Int) in
175
+ try rnFishjamClient.setScreencastTrackBandwidth(bandwidth: bandwidth)
176
+ }
177
+
178
+ AsyncFunction("setScreencastTrackEncodingBandwidth") { (encoding: String, bandwidth: Int) in
179
+ try rnFishjamClient.setScreencastTrackEncodingBandwidth(
180
+ encoding: encoding, bandwidth: bandwidth)
181
+ }
182
+
183
+ AsyncFunction("setTargetTrackEncoding") { (trackId: String, encoding: String) in
184
+ try rnFishjamClient.setTargetTrackEncoding(trackId: trackId, encoding: encoding)
185
+ }
186
+
187
+ AsyncFunction("toggleVideoTrackEncoding") { (encoding: String) in
188
+ try rnFishjamClient.toggleVideoTrackEncoding(encoding: encoding)
189
+ }
190
+
191
+ AsyncFunction("setVideoTrackEncodingBandwidth") { (encoding: String, bandwidth: Int) in
192
+ try rnFishjamClient.setVideoTrackEncodingBandwidth(
193
+ encoding: encoding, bandwidth: bandwidth)
194
+ }
195
+
196
+ AsyncFunction("setVideoTrackBandwidth") { (bandwidth: Int) in
197
+ try rnFishjamClient.setVideoTrackBandwidth(bandwidth: bandwidth)
198
+ }
199
+
200
+ AsyncFunction("changeWebRTCLoggingSeverity") { (severity: String) in
201
+ try rnFishjamClient.changeWebRTCLoggingSeverity(severity: severity)
202
+ }
203
+
204
+ AsyncFunction("getStatistics") {
205
+ try rnFishjamClient.getStatistics()
206
+ }
207
+
208
+ AsyncFunction("selectAudioSessionMode") { (sessionMode: String) in
209
+ try rnFishjamClient.selectAudioSessionMode(sessionMode: sessionMode)
210
+ }
211
+
212
+ AsyncFunction("showAudioRoutePicker") {
213
+ rnFishjamClient.showAudioRoutePicker()
214
+ }
215
+
216
+ AsyncFunction("startAudioSwitcher") {
217
+ rnFishjamClient.startAudioSwitcher()
218
+ }
219
+ }
220
+ }
@@ -0,0 +1,43 @@
1
+ import FishjamCloudClient
2
+ import ReplayKit
3
+ import os.log
4
+
5
+ let log = OSLog(subsystem: "com.fishjamcloud.react-native-client", category: "ErrorHandling")
6
+
7
+ #if os(iOS)
8
+ @available(iOS 12, *)
9
+ extension RPSystemBroadcastPickerView {
10
+ public static func show(
11
+ for preferredExtension: String? = nil, showsMicrophoneButton: Bool = false
12
+ ) {
13
+ let view = RPSystemBroadcastPickerView()
14
+ view.preferredExtension = preferredExtension
15
+ view.showsMicrophoneButton = showsMicrophoneButton
16
+
17
+ let selector = NSSelectorFromString("buttonPressed:")
18
+ if view.responds(to: selector) {
19
+ view.perform(selector, with: nil)
20
+ }
21
+ }
22
+ }
23
+ #endif
24
+
25
+ extension [String: Any] {
26
+ public func toMetadata() -> Metadata {
27
+ var res: Metadata = .init()
28
+ self.forEach { entry in
29
+ res[entry.key] = entry.value
30
+ }
31
+ return res
32
+ }
33
+ }
34
+
35
+ extension AnyJson {
36
+ public func toDict() -> [String: Any] {
37
+ var res: [String: Any] = [:]
38
+ self.keys.forEach { key in
39
+ res[key] = self[key]
40
+ }
41
+ return res
42
+ }
43
+ }
@@ -0,0 +1,64 @@
1
+ import ExpoModulesCore
2
+ import FishjamCloudClient
3
+
4
+ class VideoPreviewView: ExpoView {
5
+ var videoView: VideoView? = nil
6
+ private var localVideoTrack: LocalVideoTrack? = nil
7
+
8
+ required init(appContext: AppContext? = nil) {
9
+ super.init(appContext: appContext)
10
+ videoView = VideoView()
11
+ videoView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
12
+ videoView?.clipsToBounds = true
13
+ addSubview(videoView!)
14
+ }
15
+
16
+ override func willMove(toSuperview newSuperview: UIView?) {
17
+ super.willMove(toSuperview: newSuperview)
18
+ if newSuperview == nil {
19
+ localVideoTrack?.stop()
20
+ } else {
21
+ guard let tracks = RNFishjamClient.fishjamClient?.getLocalEndpoint().tracks else {
22
+ os_log(
23
+ "Error moving VideoPreviewView: %{public}s", log: log, type: .error,
24
+ String(describing: "No tracks available")
25
+ )
26
+ return
27
+ }
28
+
29
+ localVideoTrack =
30
+ tracks.first(where: { (key, track) in
31
+ track is LocalVideoTrack
32
+ })?.value as? LocalVideoTrack
33
+ localVideoTrack?.start()
34
+ videoView?.track = localVideoTrack
35
+ }
36
+ }
37
+
38
+ var videoLayout: String = "FILL" {
39
+ didSet {
40
+ switch videoLayout {
41
+ case "FIT":
42
+ self.videoView?.layout = .fit
43
+ case "FILL":
44
+ self.videoView?.layout = .fill
45
+ default:
46
+ self.videoView?.layout = .fill
47
+ }
48
+ }
49
+ }
50
+
51
+ var mirrorVideo: Bool = false {
52
+ didSet {
53
+ self.videoView?.mirror = mirrorVideo
54
+ }
55
+ }
56
+
57
+ var captureDeviceId: String? = nil {
58
+ didSet {
59
+ if let captureDeviceId = captureDeviceId {
60
+ localVideoTrack?.switchCamera(deviceId: captureDeviceId)
61
+ }
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,21 @@
1
+ import ExpoModulesCore
2
+
3
+ public class VideoPreviewViewModule: Module {
4
+ public func definition() -> ModuleDefinition {
5
+ Name("VideoPreviewViewModule")
6
+
7
+ View(VideoPreviewView.self) {
8
+ Prop("captureDeviceId") { (view: VideoPreviewView, prop: String) in
9
+ view.captureDeviceId = prop
10
+ }
11
+
12
+ Prop("mirrorVideo") { (view: VideoPreviewView, prop: Bool) in
13
+ view.mirrorVideo = prop
14
+ }
15
+
16
+ Prop("videoLayout") { (view: VideoPreviewView, prop: String) in
17
+ view.videoLayout = prop
18
+ }
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,84 @@
1
+ import Combine
2
+ import ExpoModulesCore
3
+ import FishjamCloudClient
4
+
5
+ protocol OnTrackUpdateListener {
6
+ func onTrackUpdate()
7
+ }
8
+
9
+ class VideoRendererView: ExpoView, OnTrackUpdateListener {
10
+ var videoView: VideoView? = nil
11
+ var cancellableEndpoints: Cancellable? = nil
12
+
13
+ required init(appContext: AppContext? = nil) {
14
+ super.init(appContext: appContext)
15
+ RNFishjamClient.onTracksUpdateListeners.append(self)
16
+ videoView = VideoView()
17
+ videoView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
18
+ videoView?.clipsToBounds = true
19
+ addSubview(videoView!)
20
+ }
21
+
22
+ deinit {
23
+ RNFishjamClient.onTracksUpdateListeners.removeAll(where: {
24
+ if let view = $0 as? VideoRendererView {
25
+ return view === self
26
+ }
27
+ return false
28
+ })
29
+ }
30
+
31
+ override func willMove(toSuperview newSuperview: UIView?) {
32
+ super.willMove(toSuperview: newSuperview)
33
+
34
+ if newSuperview != nil {
35
+ updateVideoTrack()
36
+ }
37
+ }
38
+
39
+ func updateVideoTrack() {
40
+ DispatchQueue.main.async {
41
+ if self.superview != nil {
42
+ for endpoint in RNFishjamClient.getLocalAndRemoteEndpoints() {
43
+ if let track = endpoint.tracks[self.trackId] as? VideoTrack {
44
+ if let track = track as? LocalVideoTrack {
45
+ self.mirrorVideo = track.isFrontCamera
46
+ }
47
+ self.videoView?.track = track
48
+ return
49
+ }
50
+ }
51
+ }
52
+ }
53
+ }
54
+
55
+ func onTrackUpdate() {
56
+ updateVideoTrack()
57
+ }
58
+
59
+ var trackId: String = "" {
60
+ didSet {
61
+ updateVideoTrack()
62
+ }
63
+ }
64
+
65
+ var videoLayout: String = "FILL" {
66
+ didSet {
67
+ switch videoLayout {
68
+ case "FIT":
69
+ self.videoView?.layout = .fit
70
+ case "FILL":
71
+ self.videoView?.layout = .fill
72
+ default:
73
+ self.videoView?.layout = .fill
74
+ }
75
+
76
+ }
77
+ }
78
+
79
+ var mirrorVideo: Bool = false {
80
+ didSet {
81
+ self.videoView?.mirror = mirrorVideo
82
+ }
83
+ }
84
+ }
@@ -0,0 +1,17 @@
1
+ import ExpoModulesCore
2
+
3
+ public class VideoRendererViewModule: Module {
4
+ public func definition() -> ModuleDefinition {
5
+ Name("VideoRendererViewModule")
6
+
7
+ View(VideoRendererView.self) {
8
+ Prop("trackId") { (view: VideoRendererView, prop: String) in
9
+ view.trackId = prop
10
+ }
11
+
12
+ Prop("videoLayout") { (view: VideoRendererView, prop: String) in
13
+ view.videoLayout = prop
14
+ }
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,56 @@
1
+ {
2
+ "fileScopedDeclarationPrivacy": {
3
+ "accessLevel": "private"
4
+ },
5
+ "indentation": {
6
+ "spaces": 4
7
+ },
8
+ "indentConditionalCompilationBlocks": true,
9
+ "indentSwitchCaseLabels": false,
10
+ "lineBreakAroundMultilineExpressionChainComponents": false,
11
+ "lineBreakBeforeControlFlowKeywords": false,
12
+ "lineBreakBeforeEachArgument": false,
13
+ "lineBreakBeforeEachGenericRequirement": false,
14
+ "lineLength": 120,
15
+ "maximumBlankLines": 1,
16
+ "prioritizeKeepingFunctionOutputTogether": false,
17
+ "respectsExistingLineBreaks": true,
18
+ "rules": {
19
+ "AllPublicDeclarationsHaveDocumentation": false,
20
+ "AlwaysUseLowerCamelCase": false,
21
+ "AmbiguousTrailingClosureOverload": true,
22
+ "BeginDocumentationCommentWithOneLineSummary": false,
23
+ "DoNotUseSemicolons": true,
24
+ "DontRepeatTypeInStaticProperties": true,
25
+ "FileScopedDeclarationPrivacy": true,
26
+ "FullyIndirectEnum": true,
27
+ "GroupNumericLiterals": true,
28
+ "IdentifiersMustBeASCII": true,
29
+ "NeverForceUnwrap": false,
30
+ "NeverUseForceTry": false,
31
+ "NeverUseImplicitlyUnwrappedOptionals": false,
32
+ "NoAccessLevelOnExtensionDeclaration": true,
33
+ "NoBlockComments": false,
34
+ "NoCasesWithOnlyFallthrough": true,
35
+ "NoEmptyTrailingClosureParentheses": true,
36
+ "NoLabelsInCasePatterns": true,
37
+ "NoLeadingUnderscores": false,
38
+ "NoParensAroundConditions": true,
39
+ "NoVoidReturnOnFunctionSignature": true,
40
+ "OneCasePerLine": true,
41
+ "OneVariableDeclarationPerLine": true,
42
+ "OnlyOneTrailingClosureArgument": false,
43
+ "OrderedImports": true,
44
+ "ReturnVoidInsteadOfEmptyTuple": true,
45
+ "UseEarlyExits": false,
46
+ "UseLetInEveryBoundCaseVariable": true,
47
+ "UseShorthandTypeNames": true,
48
+ "UseSingleLinePropertyGetter": true,
49
+ "UseSynthesizedInitializer": true,
50
+ "UseTripleSlashForDocumentationComments": false,
51
+ "UseWhereClausesInForLoops": false,
52
+ "ValidateDocumentationComments": false
53
+ },
54
+ "tabWidth": 8,
55
+ "version": 1
56
+ }
package/package.json ADDED
@@ -0,0 +1,89 @@
1
+ {
2
+ "name": "@fishjam-cloud/react-native-client",
3
+ "version": "0.1.0",
4
+ "description": "A React Native client for Fishjam Cloud",
5
+ "author": "Fishjam Cloud Team",
6
+ "license": "Apache-2.0",
7
+ "main": "build/index.js",
8
+ "types": "build/index.d.ts",
9
+ "scripts": {
10
+ "build": "expo-module build",
11
+ "clean": "expo-module clean",
12
+ "lint": "sh ./scripts/lint.sh",
13
+ "lint:check": "sh ./scripts/lint_check.sh",
14
+ "test": "expo-module test",
15
+ "prepare": "expo-module prepare",
16
+ "prepublishOnly": "expo-module prepublishOnly",
17
+ "expo-module": "expo-module",
18
+ "release": "release-it",
19
+ "releaseAppAndroid": "cd examples/video-chat/android && fastlane deploy",
20
+ "releaseAppIos": "cd example/ios && fastlane deploy",
21
+ "docs": "sed 's/\\.github\\/images/media/g' README.md > README_docs.md && typedoc src/index.tsx --media ./.github/images --readme README_docs.md && rm README_docs.md",
22
+ "typecheck": "yarn tsc --noEmit && cd example && yarn tsc --noEmit"
23
+ },
24
+ "keywords": [
25
+ "react-native",
26
+ "expo",
27
+ "@fishjam-cloud/react-native-client",
28
+ "fishjam-cloud",
29
+ "MembraneWebRTC",
30
+ "fishjam"
31
+ ],
32
+ "repository": "https://github.com/fishjam-cloud/mobile-client-sdk",
33
+ "bugs": {
34
+ "url": "https://github.com/fishjam-cloud/mobile-client-sdk/issues"
35
+ },
36
+ "homepage": "https://github.com/fishjam-cloud/mobile-client-sdk#readme",
37
+ "publishConfig": {
38
+ "registry": "https://registry.npmjs.org/",
39
+ "access": "public"
40
+ },
41
+ "dependencies": {
42
+ "phoenix": "^1.7.6",
43
+ "promise-fs": "^2.1.1",
44
+ "protobufjs": "^7.4.0"
45
+ },
46
+ "devDependencies": {
47
+ "@testing-library/react": "^15.0.7",
48
+ "@types/lodash": "^4.17.7",
49
+ "@types/phoenix": "^1.6.5",
50
+ "@types/promise-fs": "^2.1.2",
51
+ "@types/react": "^18.3.5",
52
+ "expo": "^50.0.20",
53
+ "expo-module-scripts": "^3.0.4",
54
+ "expo-modules-core": "~1.11.8",
55
+ "husky": "^9.1.5",
56
+ "jest": "^29.6.1",
57
+ "jest-environment-jsdom": "^29.6.1",
58
+ "jest-expo": "^50.0.2",
59
+ "jest-websocket-mock": "^2.4.0",
60
+ "lint-staged": "^15.2.10",
61
+ "pod-install": "^0.2.0",
62
+ "react": "18.3.1",
63
+ "react-dom": "18.3.1",
64
+ "react-native": "0.73.4",
65
+ "release-it": "^17.6.0",
66
+ "ts-proto": "^2.1.0",
67
+ "typedoc": "^0.26.6",
68
+ "typedoc-plugin-mark-react-functional-components": "^0.2.2",
69
+ "typescript": "^5.5.4"
70
+ },
71
+ "peerDependencies": {
72
+ "expo": "*",
73
+ "react": "*",
74
+ "react-native": "*"
75
+ },
76
+ "jest": {
77
+ "preset": "jest-expo",
78
+ "modulePathIgnorePatterns": [
79
+ "<rootDir>/example/node_modules",
80
+ "<rootDir>/lib/"
81
+ ],
82
+ "testEnvironment": "jsdom"
83
+ },
84
+ "lint-staged": {
85
+ "*.(js|ts|tsx)": [
86
+ "yarn lint:check"
87
+ ]
88
+ }
89
+ }
@@ -0,0 +1,27 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleDisplayName</key>
6
+ <string>MembraneScreenBroadcast</string>
7
+ <key>CFBundleExecutable</key>
8
+ <string>$(EXECUTABLE_NAME)</string>
9
+ <key>CFBundleIdentifier</key>
10
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11
+ <key>CFBundleName</key>
12
+ <string>$(PRODUCT_NAME)</string>
13
+ <key>CFBundlePackageType</key>
14
+ <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
15
+ <key>CFBundleVersion</key>
16
+ <string>$(CURRENT_PROJECT_VERSION)</string>
17
+ <key>NSExtension</key>
18
+ <dict>
19
+ <key>NSExtensionPointIdentifier</key>
20
+ <string>com.apple.broadcast-services-upload</string>
21
+ <key>NSExtensionPrincipalClass</key>
22
+ <string>$(PRODUCT_MODULE_NAME).MembraneBroadcastSampleHandler</string>
23
+ <key>RPBroadcastProcessMode</key>
24
+ <string>RPBroadcastProcessModeSampleBuffer</string>
25
+ </dict>
26
+ </dict>
27
+ </plist>
@@ -0,0 +1,50 @@
1
+ import FishjamClient
2
+ import Foundation
3
+ import ReplayKit
4
+ import WebRTC
5
+ import os.log
6
+
7
+ /// App Group used by the extension to exchange buffers with the target application
8
+ let appGroup = "{{GROUP_IDENTIFIER}}"
9
+
10
+ let logger = OSLog(subsystem: "{{BUNDLE_IDENTIFIER}}.MembraneBroadcastSampleHandler", category: "Broadcaster")
11
+
12
+ /// An example `SampleHandler` utilizing `BroadcastSampleSource` from `MembraneRTC` sending broadcast samples and necessary notification enabling device's screencast.
13
+ class MembraneBroadcastSampleHandler: RPBroadcastSampleHandler {
14
+ let broadcastSource = BroadcastSampleSource(appGroup: appGroup)
15
+ var started: Bool = false
16
+
17
+ override func broadcastStarted(withSetupInfo _: [String: NSObject]?) {
18
+ started = broadcastSource.connect()
19
+
20
+ guard started else {
21
+ os_log("failed to connect with ipc server", log: logger, type: .debug)
22
+
23
+ super.finishBroadcastWithError(NSError(domain: "", code: 0, userInfo: nil))
24
+
25
+ return
26
+ }
27
+
28
+ broadcastSource.started()
29
+ }
30
+
31
+ override func broadcastPaused() {
32
+ broadcastSource.paused()
33
+ }
34
+
35
+ override func broadcastResumed() {
36
+ broadcastSource.resumed()
37
+ }
38
+
39
+ override func broadcastFinished() {
40
+ broadcastSource.finished()
41
+ }
42
+
43
+ override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
44
+ guard started else {
45
+ return
46
+ }
47
+
48
+ broadcastSource.processFrame(sampleBuffer: sampleBuffer, ofType: sampleBufferType)
49
+ }
50
+ }
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>com.apple.security.application-groups</key>
6
+ <array>
7
+ <string>{{GROUP_IDENTIFIER}}</string>
8
+ </array>
9
+ </dict>
10
+ </plist>