@fishjam-cloud/react-native-client 0.23.0 → 0.25.0-rc.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.
Files changed (262) hide show
  1. package/README.md +56 -15
  2. package/dist/index.d.ts +13 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +19 -0
  5. package/dist/overrides/RTCPeerConnection.d.ts +8 -0
  6. package/dist/overrides/RTCPeerConnection.d.ts.map +1 -0
  7. package/dist/overrides/RTCPeerConnection.js +16 -0
  8. package/dist/overrides/RTCView.d.ts +11 -0
  9. package/dist/overrides/RTCView.d.ts.map +1 -0
  10. package/dist/overrides/RTCView.js +21 -0
  11. package/dist/polyfills/local-storage.d.ts +10 -0
  12. package/dist/polyfills/local-storage.d.ts.map +1 -0
  13. package/dist/polyfills/local-storage.js +24 -0
  14. package/{build/hooks → dist}/useForegroundService.d.ts +10 -10
  15. package/dist/useForegroundService.d.ts.map +1 -0
  16. package/dist/useForegroundService.js +10 -0
  17. package/dist/webrtc-polyfill.d.ts +2 -0
  18. package/dist/webrtc-polyfill.d.ts.map +1 -0
  19. package/dist/webrtc-polyfill.js +14 -0
  20. package/package.json +44 -92
  21. package/plugin/broadcastExtensionFiles/Atomic.swift +37 -0
  22. package/plugin/broadcastExtensionFiles/DarwinNotificationCenter.swift +29 -0
  23. package/plugin/broadcastExtensionFiles/Info.plist +2 -2
  24. package/plugin/broadcastExtensionFiles/SampleHandler.swift +104 -0
  25. package/plugin/broadcastExtensionFiles/SampleUploader.swift +146 -0
  26. package/plugin/broadcastExtensionFiles/SocketConnection.swift +198 -0
  27. package/plugin/build/types.d.ts +5 -3
  28. package/plugin/build/withFishjam.d.ts +31 -2
  29. package/plugin/build/withFishjam.js +32 -6
  30. package/plugin/build/withFishjamAndroid.d.ts +2 -2
  31. package/plugin/build/withFishjamAndroid.js +60 -13
  32. package/plugin/build/withFishjamIos.d.ts +3 -8
  33. package/plugin/build/withFishjamIos.js +54 -69
  34. package/plugin/src/types.ts +19 -0
  35. package/plugin/src/withFishjam.ts +42 -0
  36. package/plugin/src/withFishjamAndroid.ts +112 -0
  37. package/plugin/src/withFishjamIos.ts +336 -0
  38. package/plugin/tsconfig.json +9 -0
  39. package/plugin/tsconfig.tsbuildinfo +1 -0
  40. package/LICENSE.txt +0 -201
  41. package/android/build.gradle +0 -95
  42. package/android/src/main/AndroidManifest.xml +0 -2
  43. package/android/src/main/java/io/fishjam/reactnative/AudioDeviceKind.kt +0 -34
  44. package/android/src/main/java/io/fishjam/reactnative/AudioSwitchManager.kt +0 -61
  45. package/android/src/main/java/io/fishjam/reactnative/EmitableEvents.kt +0 -126
  46. package/android/src/main/java/io/fishjam/reactnative/Errors.kt +0 -31
  47. package/android/src/main/java/io/fishjam/reactnative/PipContainerView.kt +0 -282
  48. package/android/src/main/java/io/fishjam/reactnative/PipContainerViewModule.kt +0 -41
  49. package/android/src/main/java/io/fishjam/reactnative/PipTrackSelector.kt +0 -98
  50. package/android/src/main/java/io/fishjam/reactnative/PipViewFactory.kt +0 -186
  51. package/android/src/main/java/io/fishjam/reactnative/RNFishjamClient.kt +0 -1001
  52. package/android/src/main/java/io/fishjam/reactnative/RNFishjamClientModule.kt +0 -358
  53. package/android/src/main/java/io/fishjam/reactnative/Utils.kt +0 -11
  54. package/android/src/main/java/io/fishjam/reactnative/VideoPreviewView.kt +0 -40
  55. package/android/src/main/java/io/fishjam/reactnative/VideoPreviewViewModule.kt +0 -22
  56. package/android/src/main/java/io/fishjam/reactnative/VideoRendererView.kt +0 -76
  57. package/android/src/main/java/io/fishjam/reactnative/VideoRendererViewModule.kt +0 -33
  58. package/android/src/main/java/io/fishjam/reactnative/VideoView.kt +0 -257
  59. package/android/src/main/java/io/fishjam/reactnative/extensions/CaptureDevice.kt +0 -17
  60. package/android/src/main/java/io/fishjam/reactnative/foregroundService/FishjamForegroundService.kt +0 -101
  61. package/android/src/main/java/io/fishjam/reactnative/foregroundService/ForegroundServiceManager.kt +0 -118
  62. package/android/src/main/java/io/fishjam/reactnative/foregroundService/ForegroundServiceState.kt +0 -46
  63. package/android/src/main/java/io/fishjam/reactnative/helpers/PictureInPictureHelperFragment.kt +0 -20
  64. package/android/src/main/java/io/fishjam/reactnative/managers/ListenerManager.kt +0 -24
  65. package/android/src/main/java/io/fishjam/reactnative/managers/LocalCameraTracksChangedListenersManager.kt +0 -8
  66. package/android/src/main/java/io/fishjam/reactnative/managers/LocalTracksSwitchListenersManager.kt +0 -17
  67. package/android/src/main/java/io/fishjam/reactnative/managers/TracksUpdateListenersManager.kt +0 -7
  68. package/android/src/main/java/io/fishjam/reactnative/utils/PermissionUtils.kt +0 -45
  69. package/build/RNFishjamClientModule.d.ts +0 -106
  70. package/build/RNFishjamClientModule.d.ts.map +0 -1
  71. package/build/RNFishjamClientModule.js +0 -21
  72. package/build/RNFishjamClientModule.js.map +0 -1
  73. package/build/common/metadata.d.ts +0 -9
  74. package/build/common/metadata.d.ts.map +0 -1
  75. package/build/common/metadata.js +0 -11
  76. package/build/common/metadata.js.map +0 -1
  77. package/build/components/FishjamRoom/GridTrackItem.d.ts +0 -12
  78. package/build/components/FishjamRoom/GridTrackItem.d.ts.map +0 -1
  79. package/build/components/FishjamRoom/GridTrackItem.js +0 -56
  80. package/build/components/FishjamRoom/GridTrackItem.js.map +0 -1
  81. package/build/components/FishjamRoom/VideosGrid.d.ts +0 -3
  82. package/build/components/FishjamRoom/VideosGrid.d.ts.map +0 -1
  83. package/build/components/FishjamRoom/VideosGrid.js +0 -20
  84. package/build/components/FishjamRoom/VideosGrid.js.map +0 -1
  85. package/build/components/FishjamRoom/index.d.ts +0 -33
  86. package/build/components/FishjamRoom/index.d.ts.map +0 -1
  87. package/build/components/FishjamRoom/index.js +0 -53
  88. package/build/components/FishjamRoom/index.js.map +0 -1
  89. package/build/components/FishjamRoom/parsePeersToTracks.d.ts +0 -4
  90. package/build/components/FishjamRoom/parsePeersToTracks.d.ts.map +0 -1
  91. package/build/components/FishjamRoom/parsePeersToTracks.js +0 -37
  92. package/build/components/FishjamRoom/parsePeersToTracks.js.map +0 -1
  93. package/build/components/PipContainerView.d.ts +0 -48
  94. package/build/components/PipContainerView.d.ts.map +0 -1
  95. package/build/components/PipContainerView.js +0 -34
  96. package/build/components/PipContainerView.js.map +0 -1
  97. package/build/components/VideoPreviewView.d.ts +0 -28
  98. package/build/components/VideoPreviewView.d.ts.map +0 -1
  99. package/build/components/VideoPreviewView.js +0 -17
  100. package/build/components/VideoPreviewView.js.map +0 -1
  101. package/build/components/VideoRendererView.d.ts +0 -39
  102. package/build/components/VideoRendererView.d.ts.map +0 -1
  103. package/build/components/VideoRendererView.js +0 -25
  104. package/build/components/VideoRendererView.js.map +0 -1
  105. package/build/consts/index.d.ts +0 -5
  106. package/build/consts/index.d.ts.map +0 -1
  107. package/build/consts/index.js +0 -8
  108. package/build/consts/index.js.map +0 -1
  109. package/build/debug/common/webRTC.d.ts +0 -9
  110. package/build/debug/common/webRTC.d.ts.map +0 -1
  111. package/build/debug/common/webRTC.js +0 -11
  112. package/build/debug/common/webRTC.js.map +0 -1
  113. package/build/debug/index.d.ts +0 -4
  114. package/build/debug/index.d.ts.map +0 -1
  115. package/build/debug/index.js +0 -3
  116. package/build/debug/index.js.map +0 -1
  117. package/build/debug/stats/types.d.ts +0 -55
  118. package/build/debug/stats/types.d.ts.map +0 -1
  119. package/build/debug/stats/types.js +0 -2
  120. package/build/debug/stats/types.js.map +0 -1
  121. package/build/debug/stats/useRTCStatistics.d.ts +0 -9
  122. package/build/debug/stats/useRTCStatistics.d.ts.map +0 -1
  123. package/build/debug/stats/useRTCStatistics.js +0 -79
  124. package/build/debug/stats/useRTCStatistics.js.map +0 -1
  125. package/build/hooks/internal/useFishjamEvent.d.ts +0 -4
  126. package/build/hooks/internal/useFishjamEvent.d.ts.map +0 -1
  127. package/build/hooks/internal/useFishjamEvent.js +0 -38
  128. package/build/hooks/internal/useFishjamEvent.js.map +0 -1
  129. package/build/hooks/internal/useFishjamEventState.d.ts +0 -3
  130. package/build/hooks/internal/useFishjamEventState.d.ts.map +0 -1
  131. package/build/hooks/internal/useFishjamEventState.js +0 -18
  132. package/build/hooks/internal/useFishjamEventState.js.map +0 -1
  133. package/build/hooks/useAppScreenShare.d.ts +0 -20
  134. package/build/hooks/useAppScreenShare.d.ts.map +0 -1
  135. package/build/hooks/useAppScreenShare.js +0 -54
  136. package/build/hooks/useAppScreenShare.js.map +0 -1
  137. package/build/hooks/useAudioSettings.d.ts +0 -49
  138. package/build/hooks/useAudioSettings.d.ts.map +0 -1
  139. package/build/hooks/useAudioSettings.js +0 -70
  140. package/build/hooks/useAudioSettings.js.map +0 -1
  141. package/build/hooks/useBandwidthEstimation.d.ts +0 -14
  142. package/build/hooks/useBandwidthEstimation.d.ts.map +0 -1
  143. package/build/hooks/useBandwidthEstimation.js +0 -19
  144. package/build/hooks/useBandwidthEstimation.js.map +0 -1
  145. package/build/hooks/useCallKit.d.ts +0 -121
  146. package/build/hooks/useCallKit.d.ts.map +0 -1
  147. package/build/hooks/useCallKit.js +0 -142
  148. package/build/hooks/useCallKit.js.map +0 -1
  149. package/build/hooks/useCamera.d.ts +0 -113
  150. package/build/hooks/useCamera.d.ts.map +0 -1
  151. package/build/hooks/useCamera.js +0 -95
  152. package/build/hooks/useCamera.js.map +0 -1
  153. package/build/hooks/useConnection.d.ts +0 -73
  154. package/build/hooks/useConnection.d.ts.map +0 -1
  155. package/build/hooks/useConnection.js +0 -46
  156. package/build/hooks/useConnection.js.map +0 -1
  157. package/build/hooks/useForegroundService.d.ts.map +0 -1
  158. package/build/hooks/useForegroundService.js +0 -66
  159. package/build/hooks/useForegroundService.js.map +0 -1
  160. package/build/hooks/useMicrophone.d.ts +0 -16
  161. package/build/hooks/useMicrophone.d.ts.map +0 -1
  162. package/build/hooks/useMicrophone.js +0 -31
  163. package/build/hooks/useMicrophone.js.map +0 -1
  164. package/build/hooks/usePeerStatus.d.ts +0 -10
  165. package/build/hooks/usePeerStatus.d.ts.map +0 -1
  166. package/build/hooks/usePeerStatus.js +0 -13
  167. package/build/hooks/usePeerStatus.js.map +0 -1
  168. package/build/hooks/usePeers.d.ts +0 -98
  169. package/build/hooks/usePeers.d.ts.map +0 -1
  170. package/build/hooks/usePeers.js +0 -81
  171. package/build/hooks/usePeers.js.map +0 -1
  172. package/build/hooks/usePermissions.d.ts +0 -24
  173. package/build/hooks/usePermissions.d.ts.map +0 -1
  174. package/build/hooks/usePermissions.js +0 -61
  175. package/build/hooks/usePermissions.js.map +0 -1
  176. package/build/hooks/useReconnection.d.ts +0 -11
  177. package/build/hooks/useReconnection.d.ts.map +0 -1
  178. package/build/hooks/useReconnection.js +0 -14
  179. package/build/hooks/useReconnection.js.map +0 -1
  180. package/build/hooks/useSandbox.d.ts +0 -20
  181. package/build/hooks/useSandbox.d.ts.map +0 -1
  182. package/build/hooks/useSandbox.js +0 -54
  183. package/build/hooks/useSandbox.js.map +0 -1
  184. package/build/hooks/useScreenShare.d.ts +0 -37
  185. package/build/hooks/useScreenShare.d.ts.map +0 -1
  186. package/build/hooks/useScreenShare.js +0 -52
  187. package/build/hooks/useScreenShare.js.map +0 -1
  188. package/build/hooks/useUpdatePeerMetadata.d.ts +0 -15
  189. package/build/hooks/useUpdatePeerMetadata.d.ts.map +0 -1
  190. package/build/hooks/useUpdatePeerMetadata.js +0 -21
  191. package/build/hooks/useUpdatePeerMetadata.js.map +0 -1
  192. package/build/index.d.ts +0 -36
  193. package/build/index.d.ts.map +0 -1
  194. package/build/index.js +0 -30
  195. package/build/index.js.map +0 -1
  196. package/build/livestream/components/LivestreamStreamer.d.ts +0 -24
  197. package/build/livestream/components/LivestreamStreamer.d.ts.map +0 -1
  198. package/build/livestream/components/LivestreamStreamer.js +0 -12
  199. package/build/livestream/components/LivestreamStreamer.js.map +0 -1
  200. package/build/livestream/components/LivestreamViewer.d.ts +0 -46
  201. package/build/livestream/components/LivestreamViewer.d.ts.map +0 -1
  202. package/build/livestream/components/LivestreamViewer.js +0 -10
  203. package/build/livestream/components/LivestreamViewer.js.map +0 -1
  204. package/build/livestream/hooks/useLivestreamStreamer.d.ts +0 -65
  205. package/build/livestream/hooks/useLivestreamStreamer.d.ts.map +0 -1
  206. package/build/livestream/hooks/useLivestreamStreamer.js +0 -72
  207. package/build/livestream/hooks/useLivestreamStreamer.js.map +0 -1
  208. package/build/livestream/hooks/useLivestreamViewer.d.ts +0 -36
  209. package/build/livestream/hooks/useLivestreamViewer.d.ts.map +0 -1
  210. package/build/livestream/hooks/useLivestreamViewer.js +0 -73
  211. package/build/livestream/hooks/useLivestreamViewer.js.map +0 -1
  212. package/build/livestream/index.d.ts +0 -11
  213. package/build/livestream/index.d.ts.map +0 -1
  214. package/build/livestream/index.js +0 -6
  215. package/build/livestream/index.js.map +0 -1
  216. package/build/protos/fishjam/peer_notifications.d.ts +0 -63
  217. package/build/protos/fishjam/peer_notifications.d.ts.map +0 -1
  218. package/build/protos/fishjam/peer_notifications.js +0 -235
  219. package/build/protos/fishjam/peer_notifications.js.map +0 -1
  220. package/build/types.d.ts +0 -34
  221. package/build/types.d.ts.map +0 -1
  222. package/build/types.js +0 -2
  223. package/build/types.js.map +0 -1
  224. package/build/utils/config.d.ts +0 -6
  225. package/build/utils/config.d.ts.map +0 -1
  226. package/build/utils/config.js +0 -10
  227. package/build/utils/config.js.map +0 -1
  228. package/build/utils/errorListener.d.ts +0 -2
  229. package/build/utils/errorListener.d.ts.map +0 -1
  230. package/build/utils/errorListener.js +0 -15
  231. package/build/utils/errorListener.js.map +0 -1
  232. package/build/utils/eventPayloadValidator.d.ts +0 -3
  233. package/build/utils/eventPayloadValidator.d.ts.map +0 -1
  234. package/build/utils/eventPayloadValidator.js +0 -86
  235. package/build/utils/eventPayloadValidator.js.map +0 -1
  236. package/build/utils/getFishjamUrl.d.ts +0 -2
  237. package/build/utils/getFishjamUrl.d.ts.map +0 -1
  238. package/build/utils/getFishjamUrl.js +0 -10
  239. package/build/utils/getFishjamUrl.js.map +0 -1
  240. package/debug/package.json +0 -4
  241. package/expo-module.config.json +0 -19
  242. package/ios/CameraPermissionsRequester.swift +0 -117
  243. package/ios/Events.swift +0 -152
  244. package/ios/PictureInPictureManager.swift +0 -215
  245. package/ios/PipContainerView.swift +0 -56
  246. package/ios/PipContainerViewModule.swift +0 -48
  247. package/ios/RNFishjamClient.podspec +0 -30
  248. package/ios/RNFishjamClient.swift +0 -995
  249. package/ios/RNFishjamClientModule.swift +0 -289
  250. package/ios/RNFishjamProxy.swift +0 -12
  251. package/ios/Utils/PermissionUtils.swift +0 -16
  252. package/ios/Utils.swift +0 -23
  253. package/ios/VideoPreviewView.swift +0 -54
  254. package/ios/VideoPreviewViewModule.swift +0 -21
  255. package/ios/VideoRendererView.swift +0 -98
  256. package/ios/VideoRendererViewModule.swift +0 -23
  257. package/ios/extensions/AVCaptureDevice.swift +0 -20
  258. package/ios/managers/LocalCameraTracksChangedListenersManager.swift +0 -23
  259. package/ios/managers/TracksUpdateListenersManager.swift +0 -21
  260. package/livestream/package.json +0 -4
  261. package/plugin/broadcastExtensionFiles/FishjamBroadcastSampleHandler.swift +0 -50
  262. /package/plugin/broadcastExtensionFiles/{FishjamScreenBroadcastExtension.entitlements → ScreenBroadcastExtension.entitlements} +0 -0
@@ -0,0 +1,104 @@
1
+ //
2
+ // SampleHandler.swift
3
+ // Broadcast Extension
4
+ //
5
+ // Created by Alex-Dan Bumbu on 04.06.2021.
6
+ //
7
+
8
+ import ReplayKit
9
+
10
+ private enum Constants {
11
+ // the App Group ID value that the app and the broadcast extension targets are setup with. It differs for each app.
12
+ static let appGroupIdentifier = "{{GROUP_IDENTIFIER}}"
13
+ }
14
+
15
+ class SampleHandler: RPBroadcastSampleHandler {
16
+
17
+ private var clientConnection: SocketConnection?
18
+ private var uploader: SampleUploader?
19
+
20
+ private var frameCount: Int = 0
21
+
22
+ var socketFilePath: String {
23
+ let sharedContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: Constants.appGroupIdentifier)
24
+ return sharedContainer?.appendingPathComponent("rtc_SSFD").path ?? ""
25
+ }
26
+
27
+ override init() {
28
+ super.init()
29
+ if let connection = SocketConnection(filePath: socketFilePath) {
30
+ clientConnection = connection
31
+ setupConnection()
32
+
33
+ uploader = SampleUploader(connection: connection)
34
+ }
35
+ }
36
+
37
+ override func broadcastStarted(withSetupInfo setupInfo: [String: NSObject]?) {
38
+ // User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
39
+ frameCount = 0
40
+
41
+ DarwinNotificationCenter.shared.postNotification(.broadcastStarted)
42
+ openConnection()
43
+ }
44
+
45
+ override func broadcastPaused() {
46
+ // User has requested to pause the broadcast. Samples will stop being delivered.
47
+ }
48
+
49
+ override func broadcastResumed() {
50
+ // User has requested to resume the broadcast. Samples delivery will resume.
51
+ }
52
+
53
+ override func broadcastFinished() {
54
+ // User has requested to finish the broadcast.
55
+ DarwinNotificationCenter.shared.postNotification(.broadcastStopped)
56
+ clientConnection?.close()
57
+ }
58
+
59
+ override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
60
+ switch sampleBufferType {
61
+ case RPSampleBufferType.video:
62
+ // very simple mechanism for adjusting frame rate by using every third frame
63
+ frameCount += 1
64
+ if frameCount % 3 == 0 {
65
+ uploader?.send(sample: sampleBuffer)
66
+ }
67
+ default:
68
+ break
69
+ }
70
+ }
71
+ }
72
+
73
+ private extension SampleHandler {
74
+
75
+ func setupConnection() {
76
+ clientConnection?.didClose = { [weak self] error in
77
+ print("client connection did close \(String(describing: error))")
78
+
79
+ if let error = error {
80
+ self?.finishBroadcastWithError(error)
81
+ } else {
82
+ // the displayed failure message is more user friendly when using NSError instead of Error
83
+ let JMScreenSharingStopped = 10001
84
+ let customError = NSError(domain: RPRecordingErrorDomain, code: JMScreenSharingStopped, userInfo: [NSLocalizedDescriptionKey: "Screen sharing stopped"])
85
+ self?.finishBroadcastWithError(customError)
86
+ }
87
+ }
88
+ }
89
+
90
+ func openConnection() {
91
+ let queue = DispatchQueue(label: "broadcast.connectTimer")
92
+ let timer = DispatchSource.makeTimerSource(queue: queue)
93
+ timer.schedule(deadline: .now(), repeating: .milliseconds(100), leeway: .milliseconds(500))
94
+ timer.setEventHandler { [weak self] in
95
+ guard self?.clientConnection?.open() == true else {
96
+ return
97
+ }
98
+
99
+ timer.cancel()
100
+ }
101
+
102
+ timer.resume()
103
+ }
104
+ }
@@ -0,0 +1,146 @@
1
+ //
2
+ // SampleUploader.swift
3
+ // Broadcast Extension
4
+ //
5
+ // Created by Alex-Dan Bumbu on 22/03/2021.
6
+ // Copyright © 2021 8x8, Inc. All rights reserved.
7
+ //
8
+
9
+ import Foundation
10
+ import ReplayKit
11
+
12
+ private enum Constants {
13
+ static let bufferMaxLength = 10240
14
+ }
15
+
16
+ class SampleUploader {
17
+
18
+ private static var imageContext = CIContext(options: nil)
19
+
20
+ @Atomic private var isReady = false
21
+ private var connection: SocketConnection
22
+
23
+ private var dataToSend: Data?
24
+ private var byteIndex = 0
25
+
26
+ private let serialQueue: DispatchQueue
27
+
28
+ init(connection: SocketConnection) {
29
+ self.connection = connection
30
+ self.serialQueue = DispatchQueue(label: "{{BUNDLE_IDENTIFIER}}.broadcast.sampleUploader")
31
+
32
+ setupConnection()
33
+ }
34
+
35
+ @discardableResult func send(sample buffer: CMSampleBuffer) -> Bool {
36
+ guard isReady else {
37
+ return false
38
+ }
39
+
40
+ isReady = false
41
+
42
+ dataToSend = prepare(sample: buffer)
43
+ byteIndex = 0
44
+
45
+ serialQueue.async { [weak self] in
46
+ self?.sendDataChunk()
47
+ }
48
+
49
+ return true
50
+ }
51
+ }
52
+
53
+ private extension SampleUploader {
54
+
55
+ func setupConnection() {
56
+ connection.didOpen = { [weak self] in
57
+ self?.isReady = true
58
+ }
59
+ connection.streamHasSpaceAvailable = { [weak self] in
60
+ self?.serialQueue.async {
61
+ if let success = self?.sendDataChunk() {
62
+ self?.isReady = !success
63
+ }
64
+ }
65
+ }
66
+ }
67
+
68
+ @discardableResult func sendDataChunk() -> Bool {
69
+ guard let dataToSend = dataToSend else {
70
+ return false
71
+ }
72
+
73
+ var bytesLeft = dataToSend.count - byteIndex
74
+ var length = bytesLeft > Constants.bufferMaxLength ? Constants.bufferMaxLength : bytesLeft
75
+
76
+ length = dataToSend[byteIndex..<(byteIndex + length)].withUnsafeBytes {
77
+ guard let ptr = $0.bindMemory(to: UInt8.self).baseAddress else {
78
+ return 0
79
+ }
80
+
81
+ return connection.writeToStream(buffer: ptr, maxLength: length)
82
+ }
83
+
84
+ if length > 0 {
85
+ byteIndex += length
86
+ bytesLeft -= length
87
+
88
+ if bytesLeft == 0 {
89
+ self.dataToSend = nil
90
+ byteIndex = 0
91
+ }
92
+ } else {
93
+ print("writeBufferToStream failure")
94
+ }
95
+
96
+ return true
97
+ }
98
+
99
+ func prepare(sample buffer: CMSampleBuffer) -> Data? {
100
+ guard let imageBuffer = CMSampleBufferGetImageBuffer(buffer) else {
101
+ print("image buffer not available")
102
+ return nil
103
+ }
104
+
105
+ CVPixelBufferLockBaseAddress(imageBuffer, .readOnly)
106
+
107
+ let scaleFactor = 2.0
108
+ let width = CVPixelBufferGetWidth(imageBuffer)/Int(scaleFactor)
109
+ let height = CVPixelBufferGetHeight(imageBuffer)/Int(scaleFactor)
110
+ let orientation = CMGetAttachment(buffer, key: RPVideoSampleOrientationKey as CFString, attachmentModeOut: nil)?.uintValue ?? 0
111
+
112
+ let scaleTransform = CGAffineTransform(scaleX: CGFloat(1.0/scaleFactor), y: CGFloat(1.0/scaleFactor))
113
+ let bufferData = self.jpegData(from: imageBuffer, scale: scaleTransform)
114
+
115
+ CVPixelBufferUnlockBaseAddress(imageBuffer, .readOnly)
116
+
117
+ guard let messageData = bufferData else {
118
+ print("corrupted image buffer")
119
+ return nil
120
+ }
121
+
122
+ let httpResponse = CFHTTPMessageCreateResponse(nil, 200, nil, kCFHTTPVersion1_1).takeRetainedValue()
123
+ CFHTTPMessageSetHeaderFieldValue(httpResponse, "Content-Length" as CFString, String(messageData.count) as CFString)
124
+ CFHTTPMessageSetHeaderFieldValue(httpResponse, "Buffer-Width" as CFString, String(width) as CFString)
125
+ CFHTTPMessageSetHeaderFieldValue(httpResponse, "Buffer-Height" as CFString, String(height) as CFString)
126
+ CFHTTPMessageSetHeaderFieldValue(httpResponse, "Buffer-Orientation" as CFString, String(orientation) as CFString)
127
+
128
+ CFHTTPMessageSetBody(httpResponse, messageData as CFData)
129
+
130
+ let serializedMessage = CFHTTPMessageCopySerializedMessage(httpResponse)?.takeRetainedValue() as Data?
131
+
132
+ return serializedMessage
133
+ }
134
+
135
+ func jpegData(from buffer: CVPixelBuffer, scale scaleTransform: CGAffineTransform) -> Data? {
136
+ let image = CIImage(cvPixelBuffer: buffer).transformed(by: scaleTransform)
137
+
138
+ guard let colorSpace = image.colorSpace else {
139
+ return nil
140
+ }
141
+
142
+ let options: [CIImageRepresentationOption: Float] = [kCGImageDestinationLossyCompressionQuality as CIImageRepresentationOption: 1.0]
143
+
144
+ return SampleUploader.imageContext.jpegRepresentation(of: image, colorSpace: colorSpace, options: options)
145
+ }
146
+ }
@@ -0,0 +1,198 @@
1
+ //
2
+ // SocketConnection.swift
3
+ // Broadcast Extension
4
+ //
5
+ // Created by Alex-Dan Bumbu on 22/03/2021.
6
+ // Copyright © 2021 Atlassian Inc. All rights reserved.
7
+ //
8
+
9
+ import Foundation
10
+
11
+ class SocketConnection: NSObject {
12
+ var didOpen: (() -> Void)?
13
+ var didClose: ((Error?) -> Void)?
14
+ var streamHasSpaceAvailable: (() -> Void)?
15
+
16
+ private let filePath: String
17
+ private var socketHandle: Int32 = -1
18
+ private var address: sockaddr_un?
19
+
20
+ private var inputStream: InputStream?
21
+ private var outputStream: OutputStream?
22
+
23
+ private var networkQueue: DispatchQueue?
24
+ private var shouldKeepRunning = false
25
+
26
+ init?(filePath path: String) {
27
+ filePath = path
28
+ socketHandle = Darwin.socket(AF_UNIX, SOCK_STREAM, 0)
29
+
30
+ guard socketHandle != -1 else {
31
+ print("failure: create socket")
32
+ return nil
33
+ }
34
+ }
35
+
36
+ func open() -> Bool {
37
+ print("open socket connection")
38
+
39
+ guard FileManager.default.fileExists(atPath: filePath) else {
40
+ print("failure: socket file missing")
41
+ return false
42
+ }
43
+
44
+ guard setupAddress() == true else {
45
+ return false
46
+ }
47
+
48
+ guard connectSocket() == true else {
49
+ return false
50
+ }
51
+
52
+ setupStreams()
53
+
54
+ inputStream?.open()
55
+ outputStream?.open()
56
+
57
+ return true
58
+ }
59
+
60
+ func close() {
61
+ unscheduleStreams()
62
+
63
+ inputStream?.delegate = nil
64
+ outputStream?.delegate = nil
65
+
66
+ inputStream?.close()
67
+ outputStream?.close()
68
+
69
+ inputStream = nil
70
+ outputStream = nil
71
+ }
72
+
73
+ func writeToStream(buffer: UnsafePointer<UInt8>, maxLength length: Int) -> Int {
74
+ outputStream?.write(buffer, maxLength: length) ?? 0
75
+ }
76
+ }
77
+
78
+ extension SocketConnection: StreamDelegate {
79
+
80
+ func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
81
+ switch eventCode {
82
+ case .openCompleted:
83
+ print("client stream open completed")
84
+ if aStream == outputStream {
85
+ didOpen?()
86
+ }
87
+ case .hasBytesAvailable:
88
+ if aStream == inputStream {
89
+ var buffer: UInt8 = 0
90
+ let numberOfBytesRead = inputStream?.read(&buffer, maxLength: 1)
91
+ if numberOfBytesRead == 0 && aStream.streamStatus == .atEnd {
92
+ print("server socket closed")
93
+ close()
94
+ notifyDidClose(error: nil)
95
+ }
96
+ }
97
+ case .hasSpaceAvailable:
98
+ if aStream == outputStream {
99
+ streamHasSpaceAvailable?()
100
+ }
101
+ case .errorOccurred:
102
+ print("client stream error occurred: \(String(describing: aStream.streamError))")
103
+ close()
104
+ notifyDidClose(error: aStream.streamError)
105
+
106
+ default:
107
+ break
108
+ }
109
+ }
110
+ }
111
+
112
+ private extension SocketConnection {
113
+
114
+ func setupAddress() -> Bool {
115
+ var addr = sockaddr_un()
116
+ guard filePath.count < MemoryLayout.size(ofValue: addr.sun_path) else {
117
+ print("failure: fd path is too long")
118
+ return false
119
+ }
120
+
121
+ _ = withUnsafeMutablePointer(to: &addr.sun_path.0) { ptr in
122
+ filePath.withCString {
123
+ strncpy(ptr, $0, filePath.count)
124
+ }
125
+ }
126
+
127
+ address = addr
128
+ return true
129
+ }
130
+
131
+ func connectSocket() -> Bool {
132
+ guard var addr = address else {
133
+ return false
134
+ }
135
+
136
+ let status = withUnsafePointer(to: &addr) { ptr in
137
+ ptr.withMemoryRebound(to: sockaddr.self, capacity: 1) {
138
+ Darwin.connect(socketHandle, $0, socklen_t(MemoryLayout<sockaddr_un>.size))
139
+ }
140
+ }
141
+
142
+ guard status == noErr else {
143
+ print("failure: \(status)")
144
+ return false
145
+ }
146
+
147
+ return true
148
+ }
149
+
150
+ func setupStreams() {
151
+ var readStream: Unmanaged<CFReadStream>?
152
+ var writeStream: Unmanaged<CFWriteStream>?
153
+
154
+ CFStreamCreatePairWithSocket(kCFAllocatorDefault, socketHandle, &readStream, &writeStream)
155
+
156
+ inputStream = readStream?.takeRetainedValue()
157
+ inputStream?.delegate = self
158
+ inputStream?.setProperty(kCFBooleanTrue, forKey: Stream.PropertyKey(kCFStreamPropertyShouldCloseNativeSocket as String))
159
+
160
+ outputStream = writeStream?.takeRetainedValue()
161
+ outputStream?.delegate = self
162
+ outputStream?.setProperty(kCFBooleanTrue, forKey: Stream.PropertyKey(kCFStreamPropertyShouldCloseNativeSocket as String))
163
+
164
+ scheduleStreams()
165
+ }
166
+
167
+ func scheduleStreams() {
168
+ shouldKeepRunning = true
169
+
170
+ networkQueue = DispatchQueue.global(qos: .userInitiated)
171
+ networkQueue?.async { [weak self] in
172
+ self?.inputStream?.schedule(in: .current, forMode: .common)
173
+ self?.outputStream?.schedule(in: .current, forMode: .common)
174
+ RunLoop.current.run()
175
+
176
+ var isRunning = false
177
+
178
+ repeat {
179
+ isRunning = self?.shouldKeepRunning ?? false && RunLoop.current.run(mode: .default, before: .distantFuture)
180
+ } while (isRunning)
181
+ }
182
+ }
183
+
184
+ func unscheduleStreams() {
185
+ networkQueue?.sync { [weak self] in
186
+ self?.inputStream?.remove(from: .current, forMode: .common)
187
+ self?.outputStream?.remove(from: .current, forMode: .common)
188
+ }
189
+
190
+ shouldKeepRunning = false
191
+ }
192
+
193
+ func notifyDidClose(error: Error?) {
194
+ if didClose != nil {
195
+ didClose?(error)
196
+ }
197
+ }
198
+ }
@@ -1,15 +1,17 @@
1
1
  export type FishjamPluginOptions = {
2
2
  android?: {
3
3
  enableForegroundService?: boolean;
4
+ enableScreensharing?: boolean;
4
5
  supportsPictureInPicture?: boolean;
5
6
  };
6
7
  ios?: {
7
- iphoneDeploymentTarget?: string;
8
8
  enableScreensharing?: boolean;
9
9
  supportsPictureInPicture?: boolean;
10
- enableVoIPBackgroundMode?: boolean;
10
+ broadcastExtensionTargetName?: string;
11
+ broadcastExtensionDisplayName?: string;
11
12
  appGroupContainerId?: string;
12
13
  mainTargetName?: string;
13
- broadcastExtensionTargetName?: string;
14
+ iphoneDeploymentTarget?: string;
15
+ enableVoIPBackgroundMode?: boolean;
14
16
  };
15
17
  } | undefined;
@@ -1,4 +1,33 @@
1
- import { ConfigPlugin } from '@expo/config-plugins';
2
- import { FishjamPluginOptions } from './types';
1
+ import type { ConfigPlugin } from '@expo/config-plugins';
2
+ import type { FishjamPluginOptions } from './types';
3
+ /**
4
+ * Main Fishjam Expo config plugin.
5
+ *
6
+ * This plugin configures both iOS and Android platforms for Picture-in-Picture support.
7
+ *
8
+ * ## Usage
9
+ *
10
+ * ```json
11
+ * {
12
+ * "plugins": [
13
+ * [
14
+ * "@fishjam-cloud/react-native-client",
15
+ * {
16
+ * "android": {
17
+ * "supportsPictureInPicture": true
18
+ * },
19
+ * "ios": {
20
+ * "supportsPictureInPicture": true
21
+ * }
22
+ * }
23
+ * ]
24
+ * ]
25
+ * }
26
+ * ```
27
+ *
28
+ * @param config - Expo config object
29
+ * @param options - Plugin configuration options
30
+ * @returns Modified config object
31
+ */
3
32
  declare const withFishjam: ConfigPlugin<FishjamPluginOptions>;
4
33
  export default withFishjam;
@@ -1,13 +1,39 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  const withFishjamAndroid_1 = require("./withFishjamAndroid");
7
- const withFishjamIos_1 = __importDefault(require("./withFishjamIos"));
4
+ const withFishjamIos_1 = require("./withFishjamIos");
5
+ /**
6
+ * Main Fishjam Expo config plugin.
7
+ *
8
+ * This plugin configures both iOS and Android platforms for Picture-in-Picture support.
9
+ *
10
+ * ## Usage
11
+ *
12
+ * ```json
13
+ * {
14
+ * "plugins": [
15
+ * [
16
+ * "@fishjam-cloud/react-native-client",
17
+ * {
18
+ * "android": {
19
+ * "supportsPictureInPicture": true
20
+ * },
21
+ * "ios": {
22
+ * "supportsPictureInPicture": true
23
+ * }
24
+ * }
25
+ * ]
26
+ * ]
27
+ * }
28
+ * ```
29
+ *
30
+ * @param config - Expo config object
31
+ * @param options - Plugin configuration options
32
+ * @returns Modified config object
33
+ */
8
34
  const withFishjam = (config, options) => {
9
- (0, withFishjamAndroid_1.withFishjamAndroid)(config, options);
10
- (0, withFishjamIos_1.default)(config, options);
35
+ config = (0, withFishjamAndroid_1.withFishjamAndroid)(config, options);
36
+ config = (0, withFishjamIos_1.withFishjamIos)(config, options);
11
37
  return config;
12
38
  };
13
39
  exports.default = withFishjam;
@@ -1,3 +1,3 @@
1
- import { ConfigPlugin } from '@expo/config-plugins';
2
- import { FishjamPluginOptions } from './types';
1
+ import type { ConfigPlugin } from '@expo/config-plugins';
2
+ import type { FishjamPluginOptions } from './types';
3
3
  export declare const withFishjamAndroid: ConfigPlugin<FishjamPluginOptions>;
@@ -3,39 +3,86 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.withFishjamAndroid = void 0;
4
4
  const config_plugins_1 = require("@expo/config-plugins");
5
5
  const Manifest_1 = require("@expo/config-plugins/build/android/Manifest");
6
+ const withFishjamPictureInPicture = (config, props) => (0, config_plugins_1.withAndroidManifest)(config, (configuration) => {
7
+ const activity = config_plugins_1.AndroidConfig.Manifest.getMainActivityOrThrow(configuration.modResults);
8
+ if (props?.android?.supportsPictureInPicture) {
9
+ activity.$['android:supportsPictureInPicture'] = 'true';
10
+ }
11
+ else {
12
+ delete activity.$['android:supportsPictureInPicture'];
13
+ }
14
+ return configuration;
15
+ });
6
16
  const withFishjamForegroundService = (config, props) => (0, config_plugins_1.withAndroidManifest)(config, async (configuration) => {
7
17
  if (!props?.android?.enableForegroundService) {
8
18
  return configuration;
9
19
  }
10
20
  const mainApplication = (0, Manifest_1.getMainApplicationOrThrow)(configuration.modResults);
11
21
  mainApplication.service = mainApplication.service || [];
12
- const newService = {
22
+ const webRTCForegroundService = {
13
23
  $: {
14
- 'android:name': 'io.fishjam.reactnative.foregroundService.FishjamForegroundService',
15
- 'android:foregroundServiceType': 'camera|microphone|mediaProjection',
24
+ 'android:name': 'com.oney.WebRTCModule.foregroundService.WebRTCForegroundService',
25
+ 'android:foregroundServiceType': 'camera|microphone',
16
26
  'android:stopWithTask': 'true',
17
27
  },
18
28
  };
19
- const existingServiceIndex = mainApplication.service.findIndex((service) => service.$['android:name'] === newService.$['android:name']);
20
- if (existingServiceIndex !== -1) {
21
- mainApplication.service[existingServiceIndex] = newService;
29
+ const existingWebRTCForegroundServiceIndex = mainApplication.service.findIndex((service) => service.$['android:name'] === webRTCForegroundService.$['android:name']);
30
+ if (existingWebRTCForegroundServiceIndex !== -1) {
31
+ mainApplication.service[existingWebRTCForegroundServiceIndex] = webRTCForegroundService;
22
32
  }
23
33
  else {
24
- mainApplication.service.push(newService);
34
+ mainApplication.service.push(webRTCForegroundService);
35
+ }
36
+ if (props?.android?.enableScreensharing) {
37
+ const mediaProjectionService = {
38
+ $: {
39
+ 'android:name': 'com.oney.WebRTCModule.MediaProjectionService',
40
+ 'android:foregroundServiceType': 'mediaProjection',
41
+ 'android:stopWithTask': 'true',
42
+ },
43
+ };
44
+ const existingMediaProjectionServiceIndex = mainApplication.service.findIndex((service) => service.$['android:name'] === mediaProjectionService.$['android:name']);
45
+ if (existingMediaProjectionServiceIndex !== -1) {
46
+ mainApplication.service[existingMediaProjectionServiceIndex] = mediaProjectionService;
47
+ }
48
+ else {
49
+ mainApplication.service.push(mediaProjectionService);
50
+ }
25
51
  }
26
52
  return configuration;
27
53
  });
28
- const withFishjamPictureInPicture = (config, props) => (0, config_plugins_1.withAndroidManifest)(config, (configuration) => {
29
- const activity = config_plugins_1.AndroidConfig.Manifest.getMainActivityOrThrow(configuration.modResults);
30
- if (props?.android?.supportsPictureInPicture) {
31
- activity.$['android:supportsPictureInPicture'] = 'true';
54
+ const withFishjamForegroundServicePermission = (config, props) => (0, config_plugins_1.withAndroidManifest)(config, (configuration) => {
55
+ if (!props?.android?.enableForegroundService) {
56
+ return configuration;
32
57
  }
33
- else {
34
- delete activity.$['android:supportsPictureInPicture'];
58
+ const mainApplication = configuration.modResults;
59
+ if (!mainApplication.manifest) {
60
+ return configuration;
61
+ }
62
+ if (!mainApplication.manifest['uses-permission']) {
63
+ mainApplication.manifest['uses-permission'] = [];
35
64
  }
65
+ const permissions = mainApplication.manifest['uses-permission'];
66
+ const foregroundServicePermissions = [
67
+ 'android.permission.FOREGROUND_SERVICE',
68
+ 'android.permission.FOREGROUND_SERVICE_CAMERA',
69
+ 'android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION',
70
+ 'android.permission.FOREGROUND_SERVICE_MICROPHONE',
71
+ ];
72
+ foregroundServicePermissions.forEach((permissionName) => {
73
+ const hasPermission = permissions.some((perm) => perm.$?.['android:name'] === permissionName);
74
+ if (!hasPermission) {
75
+ permissions.push({
76
+ $: {
77
+ 'android:name': permissionName,
78
+ },
79
+ });
80
+ }
81
+ });
36
82
  return configuration;
37
83
  });
38
84
  const withFishjamAndroid = (config, props) => {
85
+ config = withFishjamForegroundServicePermission(config, props);
39
86
  config = withFishjamForegroundService(config, props);
40
87
  config = withFishjamPictureInPicture(config, props);
41
88
  return config;
@@ -1,9 +1,4 @@
1
- import { ConfigPlugin } from '@expo/config-plugins';
2
- import { FishjamPluginOptions } from './types';
3
- export declare function getSbePodfileSnippet(props: FishjamPluginOptions): string;
4
- /**
5
- * Applies screen sharing plugin if enabled. In order for screensharing to work, we need to copy extension files to your iOS project.
6
- * Allows for dynamically changing deploymentTarget.
7
- */
1
+ import type { ConfigPlugin } from '@expo/config-plugins';
2
+ import type { FishjamPluginOptions } from './types';
8
3
  declare const withFishjamIos: ConfigPlugin<FishjamPluginOptions>;
9
- export default withFishjamIos;
4
+ export { withFishjamIos };