@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
@@ -1 +0,0 @@
1
- {"version":3,"file":"eventPayloadValidator.d.ts","sourceRoot":"","sources":["../../src/utils/eventPayloadValidator.ts"],"names":[],"mappings":"AACA,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EACjB,MAAM,0BAA0B,CAAC;AAyClC,wBAAgB,0BAA0B,CACxC,CAAC,SAAS,MAAM,OAAO,gBAAgB,EACvC,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAAG,IAAI,CA8DzD"}
@@ -1,86 +0,0 @@
1
- import { z } from 'zod';
2
- import { ReceivableEvents, } from '../RNFishjamClientModule';
3
- const SimulcastConfigSchema = z.object({
4
- enabled: z.boolean(),
5
- activeEncodings: z.array(z.enum(['l', 'm', 'h'])),
6
- });
7
- const AudioOutputDeviceSchema = z.object({
8
- name: z.string(),
9
- type: z.enum(['bluetooth', 'headset', 'speaker', 'earpiece']),
10
- });
11
- const AudioDeviceEventSchema = z.object({
12
- availableDevices: z.array(AudioOutputDeviceSchema),
13
- selectedDevice: AudioOutputDeviceSchema.nullable(),
14
- });
15
- const CameraSchema = z.object({
16
- id: z.string(),
17
- name: z.string(),
18
- facingDirection: z.enum(['front', 'back', 'unspecified']),
19
- });
20
- const CameraChangedEventSchema = z.object({
21
- isCameraOn: z.boolean(),
22
- currentCamera: CameraSchema.nullable(),
23
- });
24
- const TrackAspectRatioUpdatedEventSchema = z.object({
25
- trackId: z.string(),
26
- aspectRatio: z.number(),
27
- });
28
- const CallKitActionSchema = z.union([
29
- z.object({ started: z.null() }),
30
- z.object({ ended: z.null() }),
31
- z.object({ failed: z.string() }),
32
- z.object({ muted: z.boolean() }),
33
- z.object({ held: z.boolean() }),
34
- ]);
35
- export function validateNativeEventPayload(eventName, payload) {
36
- switch (eventName) {
37
- case ReceivableEvents.IsMicrophoneOn:
38
- case ReceivableEvents.IsScreenShareOn:
39
- case ReceivableEvents.IsAppScreenShareOn:
40
- z.boolean().parse(payload);
41
- break;
42
- case ReceivableEvents.SimulcastConfigUpdate:
43
- SimulcastConfigSchema.parse(payload);
44
- break;
45
- case ReceivableEvents.PeersUpdate:
46
- break;
47
- case ReceivableEvents.AudioDeviceUpdate:
48
- AudioDeviceEventSchema.parse(payload);
49
- break;
50
- case ReceivableEvents.BandwidthEstimation:
51
- z.number().nullable().parse(payload);
52
- break;
53
- case ReceivableEvents.ReconnectionRetriesLimitReached:
54
- case ReceivableEvents.ReconnectionStarted:
55
- case ReceivableEvents.Reconnected:
56
- z.undefined().parse(payload);
57
- break;
58
- case ReceivableEvents.Warning:
59
- z.string().parse(payload);
60
- break;
61
- case ReceivableEvents.PeerStatusChanged:
62
- z.enum(['connecting', 'connected', 'error', 'idle']).parse(payload);
63
- break;
64
- case ReceivableEvents.ReconnectionStatusChanged:
65
- z.enum([
66
- 'connecting',
67
- 'connected',
68
- 'error',
69
- 'reconnecting',
70
- 'idle',
71
- ]).parse(payload);
72
- break;
73
- case ReceivableEvents.CurrentCameraChanged:
74
- CameraChangedEventSchema.parse(payload);
75
- break;
76
- case ReceivableEvents.TrackAspectRatioUpdated:
77
- TrackAspectRatioUpdatedEventSchema.parse(payload);
78
- break;
79
- case ReceivableEvents.CallKitActionPerformed:
80
- CallKitActionSchema.parse(payload);
81
- break;
82
- default:
83
- throw new Error(`Unknown event: ${eventName}`);
84
- }
85
- }
86
- //# sourceMappingURL=eventPayloadValidator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"eventPayloadValidator.js","sourceRoot":"","sources":["../../src/utils/eventPayloadValidator.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod';\nimport {\n ReceivableEventPayloads,\n ReceivableEvents,\n} from '../RNFishjamClientModule';\n\nconst SimulcastConfigSchema = z.object({\n enabled: z.boolean(),\n activeEncodings: z.array(z.enum(['l', 'm', 'h'])),\n});\n\nconst AudioOutputDeviceSchema = z.object({\n name: z.string(),\n type: z.enum(['bluetooth', 'headset', 'speaker', 'earpiece']),\n});\n\nconst AudioDeviceEventSchema = z.object({\n availableDevices: z.array(AudioOutputDeviceSchema),\n selectedDevice: AudioOutputDeviceSchema.nullable(),\n});\n\nconst CameraSchema = z.object({\n id: z.string(),\n name: z.string(),\n facingDirection: z.enum(['front', 'back', 'unspecified']),\n});\n\nconst CameraChangedEventSchema = z.object({\n isCameraOn: z.boolean(),\n currentCamera: CameraSchema.nullable(),\n});\n\nconst TrackAspectRatioUpdatedEventSchema = z.object({\n trackId: z.string(),\n aspectRatio: z.number(),\n});\n\nconst CallKitActionSchema = z.union([\n z.object({ started: z.null() }),\n z.object({ ended: z.null() }),\n z.object({ failed: z.string() }),\n z.object({ muted: z.boolean() }),\n z.object({ held: z.boolean() }),\n]);\n\nexport function validateNativeEventPayload<\n T extends keyof typeof ReceivableEvents,\n>(eventName: T, payload: ReceivableEventPayloads[T]): void {\n switch (eventName) {\n case ReceivableEvents.IsMicrophoneOn:\n case ReceivableEvents.IsScreenShareOn:\n case ReceivableEvents.IsAppScreenShareOn:\n z.boolean().parse(payload);\n break;\n\n case ReceivableEvents.SimulcastConfigUpdate:\n SimulcastConfigSchema.parse(payload);\n break;\n\n case ReceivableEvents.PeersUpdate:\n break;\n\n case ReceivableEvents.AudioDeviceUpdate:\n AudioDeviceEventSchema.parse(payload);\n break;\n\n case ReceivableEvents.BandwidthEstimation:\n z.number().nullable().parse(payload);\n break;\n\n case ReceivableEvents.ReconnectionRetriesLimitReached:\n case ReceivableEvents.ReconnectionStarted:\n case ReceivableEvents.Reconnected:\n z.undefined().parse(payload);\n break;\n\n case ReceivableEvents.Warning:\n z.string().parse(payload);\n break;\n\n case ReceivableEvents.PeerStatusChanged:\n z.enum(['connecting', 'connected', 'error', 'idle']).parse(payload);\n break;\n\n case ReceivableEvents.ReconnectionStatusChanged:\n z.enum([\n 'connecting',\n 'connected',\n 'error',\n 'reconnecting',\n 'idle',\n ]).parse(payload);\n break;\n\n case ReceivableEvents.CurrentCameraChanged:\n CameraChangedEventSchema.parse(payload);\n break;\n\n case ReceivableEvents.TrackAspectRatioUpdated:\n TrackAspectRatioUpdatedEventSchema.parse(payload);\n break;\n\n case ReceivableEvents.CallKitActionPerformed:\n CallKitActionSchema.parse(payload);\n break;\n\n default:\n throw new Error(`Unknown event: ${eventName}`);\n }\n}\n"]}
@@ -1,2 +0,0 @@
1
- export declare const getFishjamUrl: (fishjamId: string) => string;
2
- //# sourceMappingURL=getFishjamUrl.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"getFishjamUrl.d.ts","sourceRoot":"","sources":["../../src/utils/getFishjamUrl.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,aAAa,GAAI,WAAW,MAAM,KAAG,MAMjD,CAAC"}
@@ -1,10 +0,0 @@
1
- import { FISHJAM_HTTP_CONNECT_URL } from '../consts';
2
- export const getFishjamUrl = (fishjamId) => {
3
- try {
4
- return new URL(fishjamId).href;
5
- }
6
- catch {
7
- return `${FISHJAM_HTTP_CONNECT_URL}/${fishjamId}`;
8
- }
9
- };
10
- //# sourceMappingURL=getFishjamUrl.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"getFishjamUrl.js","sourceRoot":"","sources":["../../src/utils/getFishjamUrl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAErD,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,SAAiB,EAAU,EAAE;IACzD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,wBAAwB,IAAI,SAAS,EAAE,CAAC;IACpD,CAAC;AACH,CAAC,CAAC","sourcesContent":["import { FISHJAM_HTTP_CONNECT_URL } from '../consts';\n\nexport const getFishjamUrl = (fishjamId: string): string => {\n try {\n return new URL(fishjamId).href;\n } catch {\n return `${FISHJAM_HTTP_CONNECT_URL}/${fishjamId}`;\n }\n};\n"]}
@@ -1,4 +0,0 @@
1
- {
2
- "main": "../build/debug/index.js",
3
- "types": "../build/debug/index.d.ts"
4
- }
@@ -1,19 +0,0 @@
1
- {
2
- "platforms": ["ios", "android", "web"],
3
- "ios": {
4
- "modules": [
5
- "RNFishjamClientModule",
6
- "VideoPreviewViewModule",
7
- "VideoRendererViewModule",
8
- "PipContainerViewModule"
9
- ]
10
- },
11
- "android": {
12
- "modules": [
13
- "io.fishjam.reactnative.RNFishjamClientModule",
14
- "io.fishjam.reactnative.VideoPreviewViewModule",
15
- "io.fishjam.reactnative.VideoRendererViewModule",
16
- "io.fishjam.reactnative.PipContainerViewModule"
17
- ]
18
- }
19
- }
@@ -1,117 +0,0 @@
1
- import ExpoModulesCore
2
- import AVFoundation
3
-
4
- let cameraKey = "NSCameraUsageDescription"
5
- let microphoneKey = "NSMicrophoneUsageDescription"
6
-
7
- protocol BaseCameraRequester {
8
- var mediaType: AVMediaType { get }
9
- func permissionWith(status systemStatus: AVAuthorizationStatus) -> [AnyHashable: Any]
10
- func permissions(for key: String, service: String) -> [AnyHashable: Any]
11
- func requestAccess(handler: @escaping (Bool) -> Void)
12
- }
13
-
14
- extension BaseCameraRequester {
15
- public func permissions(for key: String, service: String) -> [AnyHashable: Any] {
16
- var systemStatus: AVAuthorizationStatus
17
- let description = Bundle.main.infoDictionary?[key] as? String
18
-
19
- if description != nil {
20
- systemStatus = AVCaptureDevice.authorizationStatus(for: mediaType)
21
- } else {
22
- RNFishjamClient.sendEvent?(EmitableEvent.warning(message: "Camera permission not granted."))
23
- systemStatus = .denied
24
- }
25
-
26
- return permissionWith(status: systemStatus)
27
- }
28
-
29
- public func permissionWith(status systemStatus: AVAuthorizationStatus) -> [AnyHashable: Any] {
30
- var status: EXPermissionStatus
31
-
32
- switch systemStatus {
33
- case .authorized:
34
- status = EXPermissionStatusGranted
35
- case .denied, .restricted:
36
- status = EXPermissionStatusDenied
37
- case .notDetermined:
38
- fallthrough
39
- @unknown default:
40
- status = EXPermissionStatusUndetermined
41
- }
42
-
43
- return [
44
- "status": status.rawValue
45
- ]
46
- }
47
-
48
- public func requestAccess(handler: @escaping (Bool) -> Void) {
49
- AVCaptureDevice.requestAccess(for: mediaType, completionHandler: handler)
50
- }
51
- }
52
-
53
- public class CameraOnlyPermissionRequester: NSObject, EXPermissionsRequester, BaseCameraRequester {
54
- let mediaType: AVMediaType = .video
55
-
56
- public static func permissionType() -> String {
57
- "camera"
58
- }
59
-
60
- public func getPermissions() -> [AnyHashable: Any] {
61
- return permissions(for: cameraKey, service: "video")
62
- }
63
-
64
- public func requestPermissions(resolver resolve: @escaping EXPromiseResolveBlock, rejecter reject: EXPromiseRejectBlock) {
65
- requestAccess { [weak self] _ in
66
- resolve(self?.getPermissions())
67
- }
68
- }
69
- }
70
-
71
- public class CameraPermissionRequester: NSObject, EXPermissionsRequester, BaseCameraRequester {
72
- let mediaType: AVMediaType = .video
73
-
74
- public static func permissionType() -> String {
75
- "camera"
76
- }
77
-
78
- public func getPermissions() -> [AnyHashable: Any] {
79
- var systemStatus: AVAuthorizationStatus
80
-
81
- let cameraUsuageDescription = Bundle.main.infoDictionary?[cameraKey] as? String
82
- let microphoneUsuageDescription = Bundle.main.infoDictionary?[microphoneKey] as? String
83
-
84
- if let cameraUsuageDescription, let microphoneUsuageDescription {
85
- systemStatus = AVCaptureDevice.authorizationStatus(for: mediaType)
86
- } else {
87
- RNFishjamClient.sendEvent?(EmitableEvent.warning(message: "Camera permission not granted."))
88
- systemStatus = .denied
89
- }
90
-
91
- return permissionWith(status: systemStatus)
92
- }
93
-
94
- public func requestPermissions(resolver resolve: @escaping EXPromiseResolveBlock, rejecter reject: EXPromiseRejectBlock) {
95
- requestAccess { [weak self] _ in
96
- resolve(self?.getPermissions())
97
- }
98
- }
99
- }
100
-
101
- public class CameraMicrophonePermissionRequester: NSObject, EXPermissionsRequester, BaseCameraRequester {
102
- let mediaType: AVMediaType = .audio
103
-
104
- public static func permissionType() -> String {
105
- "microphone"
106
- }
107
-
108
- public func getPermissions() -> [AnyHashable: Any] {
109
- return permissions(for: microphoneKey, service: "audio")
110
- }
111
-
112
- public func requestPermissions(resolver resolve: @escaping EXPromiseResolveBlock, rejecter reject: EXPromiseRejectBlock) {
113
- requestAccess { [weak self] _ in
114
- resolve(self?.getPermissions())
115
- }
116
- }
117
- }
package/ios/Events.swift DELETED
@@ -1,152 +0,0 @@
1
- import AVKit
2
- import FishjamCloudClient
3
-
4
- enum PeerStatus: String {
5
- case connecting
6
- case connected
7
- case error
8
- case idle
9
- }
10
-
11
- enum CallKitAction {
12
- case started
13
- case ended
14
- case failed(String)
15
- case held(Bool)
16
- case muted(Bool)
17
- }
18
-
19
- class EmitableEvent {
20
- enum EventName: String, CaseIterable {
21
- case IsMicrophoneOn
22
- case IsScreenShareOn
23
- case IsAppScreenShareOn
24
- case SimulcastConfigUpdate
25
- case PeersUpdate
26
- case AudioDeviceUpdate
27
- case BandwidthEstimation
28
- case Warning
29
- case PeerStatusChanged
30
- case ReconnectionStatusChanged
31
- case CurrentCameraChanged
32
- case TrackAspectRatioUpdated
33
- case CallKitActionPerformed
34
-
35
- var name: String {
36
- rawValue
37
- }
38
- }
39
-
40
- let event: EventName
41
- let eventContent: Any?
42
-
43
- var data: [String: Any?] {
44
- [event.name: eventContent]
45
- }
46
-
47
- private init(event: EventName, eventContent: Any? = nil) {
48
- self.event = event
49
- self.eventContent = eventContent
50
- }
51
-
52
- static func isMicrophoneOn(enabled: Bool) -> EmitableEvent { .init(event: .IsMicrophoneOn, eventContent: enabled) }
53
- static func isScreenShareOn(enabled: Bool) -> EmitableEvent {
54
- .init(event: .IsScreenShareOn, eventContent: enabled)
55
- }
56
- static func isAppScreenShareOn(enabled: Bool) -> EmitableEvent {
57
- .init(event: .IsAppScreenShareOn, eventContent: enabled)
58
- }
59
- static func bandwidthEstimation(estimation: Int) -> EmitableEvent {
60
- .init(event: .BandwidthEstimation, eventContent: estimation)
61
- }
62
- static func warning(message: String) -> EmitableEvent { .init(event: .Warning, eventContent: message) }
63
- static func peerStatusChanged(peerStatus: PeerStatus) -> EmitableEvent {
64
- .init(event: .PeerStatusChanged, eventContent: peerStatus.rawValue)
65
- }
66
- static func reconnectionStatusChanged(reconnectionStatus: ReconnectionStatus) -> EmitableEvent {
67
- .init(event: .ReconnectionStatusChanged, eventContent: reconnectionStatus.rawValue)
68
- }
69
-
70
- static func currentCameraChanged(localCamera: LocalCamera?, isCameraOn: Bool, isCameraInitialized: Bool)
71
- -> EmitableEvent
72
- {
73
- return .init(
74
- event: .CurrentCameraChanged,
75
- eventContent: [
76
- "currentCamera": localCamera as Any,
77
- "isCameraOn": isCameraOn,
78
- "isCameraInitialized": isCameraInitialized,
79
- ])
80
- }
81
-
82
- static func simulcastConfigUpdate(simulcastConfig: SimulcastConfig) -> EmitableEvent {
83
- return .init(
84
- event: .SimulcastConfigUpdate,
85
- eventContent: [
86
- "enabled": simulcastConfig.enabled,
87
- "activeEncodings": simulcastConfig.activeEncodings.map { e in e.description },
88
- ])
89
- }
90
-
91
- static func peersUpdate() -> EmitableEvent {
92
- return .init(event: .PeersUpdate)
93
- }
94
-
95
- static func trackAspectRatioUpdated(trackId: String, aspectRatio: Double?) -> EmitableEvent {
96
- return .init(
97
- event: .TrackAspectRatioUpdated,
98
- eventContent: [
99
- "trackId": trackId,
100
- "aspectRatio": aspectRatio as Any,
101
- ])
102
- }
103
-
104
- static func audioDeviceUpdate(currentRoute: AVAudioSessionRouteDescription) -> EmitableEvent {
105
- guard let output = currentRoute.outputs.first else {
106
- return .init(
107
- event: .AudioDeviceUpdate,
108
- eventContent: [
109
- "selectedDevice": nil,
110
- "availableDevices": [],
111
- ])
112
- }
113
- let deviceType = output.portType
114
-
115
- let deviceTypeString =
116
- switch deviceType {
117
- case .bluetoothA2DP, .bluetoothLE, .bluetoothHFP: "bluetooth"
118
- case .builtInSpeaker: "speaker"
119
- case .builtInReceiver: "earpiece"
120
- case .headphones: "headphones"
121
- default: deviceType.rawValue
122
- }
123
-
124
- return .init(
125
- event: .AudioDeviceUpdate,
126
- eventContent: [
127
- "selectedDevice": ["name": output.portName, "type": deviceTypeString],
128
- "availableDevices": [],
129
- ])
130
- }
131
-
132
- static func callKitActionPerformed(_ action: CallKitAction) -> EmitableEvent {
133
- let eventContent: [String: Any?]
134
- switch action {
135
- case .started:
136
- eventContent = ["started": nil]
137
- case .ended:
138
- eventContent = ["ended": nil]
139
- case .failed(let reason):
140
- eventContent = ["failed": reason]
141
- case .muted(let isMuted):
142
- eventContent = ["muted": isMuted]
143
- case .held(let isOnHold):
144
- eventContent = ["held": isOnHold]
145
- }
146
- return .init(event: .CallKitActionPerformed, eventContent: eventContent)
147
- }
148
-
149
- static var allEvents: [String] {
150
- EventName.allCases.map(\.name)
151
- }
152
- }
@@ -1,215 +0,0 @@
1
- import AVKit
2
- import FishjamCloudClient
3
- import WebRTC
4
-
5
- @MainActor
6
- class PictureInPictureManager {
7
- private let sourceView: UIView
8
- private let eventEmitter: (EmitableEvent) -> Void
9
- private weak var fishjamClient: FishjamClient?
10
- private var lastActiveVadInfo: RemoteTrackInfo? = nil
11
-
12
- private var controller: PictureInPictureController?
13
-
14
- private var startAutomatically: Bool {
15
- didSet {
16
- controller?.startAutomatically = startAutomatically
17
- }
18
- }
19
-
20
- private var stopAutomatically: Bool {
21
- didSet {
22
- controller?.stopAutomatically = stopAutomatically
23
- }
24
- }
25
-
26
- var primaryPlaceholderText: String = "No camera" {
27
- didSet {
28
- controller?.primaryPlaceholderText = primaryPlaceholderText
29
- }
30
- }
31
-
32
- var secondaryPlaceholderText: String = "No active speaker" {
33
- didSet {
34
- controller?.secondaryPlaceholderText = secondaryPlaceholderText
35
- }
36
- }
37
-
38
- init(
39
- sourceView: UIView,
40
- eventEmitter: @escaping (EmitableEvent) -> Void,
41
- fishjamClient: FishjamClient?
42
- ) {
43
- self.sourceView = sourceView
44
- self.eventEmitter = eventEmitter
45
- self.fishjamClient = fishjamClient
46
- self.startAutomatically = true
47
- self.stopAutomatically = true
48
-
49
- RNFishjamClient.tracksUpdateListenersManager.add(self)
50
- }
51
-
52
- deinit {
53
- RNFishjamClient.tracksUpdateListenersManager.remove(self)
54
- }
55
-
56
- @discardableResult
57
- private func ensureController() -> PictureInPictureController? {
58
- if controller == nil {
59
- let newController = PictureInPictureController(
60
- sourceView: sourceView,
61
- primaryPlaceholder: primaryPlaceholderText,
62
- secondaryPlaceholder: secondaryPlaceholderText
63
- )
64
- newController.startAutomatically = startAutomatically
65
- newController.stopAutomatically = stopAutomatically
66
- controller = newController
67
-
68
- updateTracks()
69
- }
70
- return controller
71
- }
72
-
73
- private func findLocalCameraTrack() -> RTCVideoTrack? {
74
- guard let fishjamClient = fishjamClient else { return nil }
75
-
76
- let localEndpoint = fishjamClient.getLocalEndpoint()
77
-
78
- for (_, track) in localEndpoint.tracks {
79
- if let videoTrack = track as? LocalVideoTrack,
80
- track.metadata.toDict()["type"] as? String == "camera" {
81
- return videoTrack.mediaTrack as? RTCVideoTrack
82
- }
83
- }
84
-
85
- return nil
86
- }
87
-
88
- private func findRemoteVadActiveTrack() -> RemoteTrackInfo? {
89
- guard let fishjamClient else { return nil }
90
-
91
- let remoteEndpoints = fishjamClient.getRemoteEndpoints()
92
-
93
- // First pass: look for active VAD
94
- for endpoint in remoteEndpoints {
95
- // Check if this endpoint has an active VAD audio track
96
- let hasActiveVad = endpoint.tracks.values.contains { track in
97
- if let audioTrack = track as? RemoteAudioTrack {
98
- return audioTrack.vadStatus == .speech
99
- }
100
- return false
101
- }
102
-
103
- if hasActiveVad {
104
- let videoTrack = endpoint.tracks.values.first { track in
105
- track is RemoteVideoTrack
106
- } as? RemoteVideoTrack
107
- lastActiveVadInfo = trackToTrackInfo(videoTrack: videoTrack, endpoint: endpoint)
108
- return lastActiveVadInfo
109
- }
110
- }
111
- if lastActiveVadInfo != nil {
112
- return lastActiveVadInfo
113
- }
114
-
115
- // Fallback: return first available remote peer with video track
116
- for endpoint in remoteEndpoints {
117
- if let videoTrack = endpoint.tracks.values.first(where: { $0 is RemoteVideoTrack }) as? RemoteVideoTrack {
118
- return trackToTrackInfo(videoTrack: videoTrack, endpoint: endpoint)
119
- }
120
- }
121
-
122
- return nil
123
- }
124
-
125
- private func trackToTrackInfo(videoTrack: RemoteVideoTrack?, endpoint: Endpoint) -> RemoteTrackInfo {
126
- let metadataDict = endpoint.metadata.toDict()
127
- let peerMetadata = metadataDict["peer"] as? [String: String]
128
- let displayName = peerMetadata?["displayName"] ?? peerMetadata?["name"]
129
-
130
- var isVideoTrackActive: Bool? = nil
131
- if videoTrack?.metadata["active"] as? Bool == false { isVideoTrackActive = false }
132
- if videoTrack?.metadata["paused"] as? Bool == true { isVideoTrackActive = false }
133
-
134
- return RemoteTrackInfo(
135
- videoTrack: videoTrack?.mediaTrack as? RTCVideoTrack,
136
- displayName: displayName,
137
- hasVideoTrack: videoTrack != nil,
138
- isVideoActive: isVideoTrackActive ?? true
139
- )
140
- }
141
-
142
- private func updateTracks() {
143
- guard let pipController = controller else { return }
144
-
145
- let localCameraTrack = findLocalCameraTrack()
146
- let remoteTrackInfo = findRemoteVadActiveTrack()
147
-
148
- pipController.primaryVideoTrack = localCameraTrack
149
- pipController.updateSecondaryTrack(trackInfo: remoteTrackInfo)
150
- }
151
-
152
-
153
-
154
- private func emitWarning(_ message: String) {
155
- eventEmitter(.warning(message: message))
156
- }
157
-
158
-
159
- func start() {
160
- _ = ensureController()
161
- controller?.startPictureInPicture()
162
- }
163
-
164
- func stop() {
165
- controller?.stopPictureInPicture()
166
- lastActiveVadInfo = nil
167
- }
168
-
169
- func setAllowsCameraWhileInPictureInPicture(_ enabled: Bool) {
170
- guard let fishjamClient = fishjamClient else {
171
- emitWarning("PictureInPicture: Fishjam client not available")
172
- return
173
- }
174
-
175
- let localEndpoint = fishjamClient.getLocalEndpoint()
176
- guard let cameraTrack = localEndpoint.tracks.compactMap({ $0.value as? LocalCameraTrack }).first else {
177
- emitWarning("PictureInPicture: Unable to configure background camera - camera not initialized")
178
- return
179
- }
180
-
181
- guard cameraTrack.isMultitaskingCameraAccessSupported() else {
182
- emitWarning("PictureInPicture: Background camera is not supported on this device.")
183
- return
184
- }
185
-
186
- cameraTrack.setMultitaskingCameraAccessEnabled(enabled)
187
- }
188
-
189
- func setStartAutomatically(_ enabled: Bool) {
190
- if enabled {
191
- ensureController()
192
- }
193
- startAutomatically = enabled
194
- controller?.startAutomatically = enabled
195
- }
196
-
197
- func setStopAutomatically(_ enabled: Bool) {
198
- stopAutomatically = enabled
199
- controller?.stopAutomatically = enabled
200
- }
201
-
202
- func cleanup() {
203
- controller?.stopPictureInPicture()
204
- controller = nil
205
- lastActiveVadInfo = nil
206
- }
207
- }
208
-
209
- extension PictureInPictureManager: TrackUpdateListener {
210
- nonisolated func onTracksUpdate() {
211
- Task { @MainActor in
212
- updateTracks()
213
- }
214
- }
215
- }