@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.
- package/.eslintignore +7 -0
- package/.eslintrc +6 -0
- package/.prettierrc +9 -0
- package/.watchmanconfig +1 -0
- package/android/.editorconfig +9 -0
- package/android/build.gradle +89 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/org/membraneframework/reactnative/AudioDeviceKind.kt +34 -0
- package/android/src/main/java/org/membraneframework/reactnative/AudioSwitchManager.kt +61 -0
- package/android/src/main/java/org/membraneframework/reactnative/EmitableEvents.kt +14 -0
- package/android/src/main/java/org/membraneframework/reactnative/Errors.kt +31 -0
- package/android/src/main/java/org/membraneframework/reactnative/RNFishjamClient.kt +866 -0
- package/android/src/main/java/org/membraneframework/reactnative/RNFishjamClientModule.kt +294 -0
- package/android/src/main/java/org/membraneframework/reactnative/Utils.kt +11 -0
- package/android/src/main/java/org/membraneframework/reactnative/VideoPreviewView.kt +40 -0
- package/android/src/main/java/org/membraneframework/reactnative/VideoPreviewViewModule.kt +17 -0
- package/android/src/main/java/org/membraneframework/reactnative/VideoRendererView.kt +58 -0
- package/android/src/main/java/org/membraneframework/reactnative/VideoRendererViewModule.kt +25 -0
- package/android/src/main/java/org/membraneframework/reactnative/VideoView.kt +77 -0
- package/app.plugin.js +1 -0
- package/babel.config.js +2 -0
- package/build/RNFishjamClientModule.d.ts +47 -0
- package/build/RNFishjamClientModule.d.ts.map +1 -0
- package/build/RNFishjamClientModule.js +4 -0
- package/build/RNFishjamClientModule.js.map +1 -0
- package/build/common/client.d.ts +19 -0
- package/build/common/client.d.ts.map +1 -0
- package/build/common/client.js +8 -0
- package/build/common/client.js.map +1 -0
- package/build/common/eventEmitter.d.ts +16 -0
- package/build/common/eventEmitter.d.ts.map +1 -0
- package/build/common/eventEmitter.js +17 -0
- package/build/common/eventEmitter.js.map +1 -0
- package/build/common/metadata.d.ts +7 -0
- package/build/common/metadata.d.ts.map +1 -0
- package/build/common/metadata.js +9 -0
- package/build/common/metadata.js.map +1 -0
- package/build/common/webRTC.d.ts +19 -0
- package/build/common/webRTC.d.ts.map +1 -0
- package/build/common/webRTC.js +22 -0
- package/build/common/webRTC.js.map +1 -0
- package/build/components/VideoPreviewView.d.ts +21 -0
- package/build/components/VideoPreviewView.d.ts.map +1 -0
- package/build/components/VideoPreviewView.js +7 -0
- package/build/components/VideoPreviewView.js.map +1 -0
- package/build/components/VideoRendererView.d.ts +19 -0
- package/build/components/VideoRendererView.d.ts.map +1 -0
- package/build/components/VideoRendererView.js +7 -0
- package/build/components/VideoRendererView.js.map +1 -0
- package/build/hooks/useAudioSettings.d.ts +23 -0
- package/build/hooks/useAudioSettings.d.ts.map +1 -0
- package/build/hooks/useAudioSettings.js +72 -0
- package/build/hooks/useAudioSettings.js.map +1 -0
- package/build/hooks/useBandwidthEstimation.d.ts +12 -0
- package/build/hooks/useBandwidthEstimation.d.ts.map +1 -0
- package/build/hooks/useBandwidthEstimation.js +16 -0
- package/build/hooks/useBandwidthEstimation.js.map +1 -0
- package/build/hooks/useCamera.d.ts +80 -0
- package/build/hooks/useCamera.d.ts.map +1 -0
- package/build/hooks/useCamera.js +140 -0
- package/build/hooks/useCamera.js.map +1 -0
- package/build/hooks/useMicrophone.d.ts +8 -0
- package/build/hooks/useMicrophone.d.ts.map +1 -0
- package/build/hooks/useMicrophone.js +27 -0
- package/build/hooks/useMicrophone.js.map +1 -0
- package/build/hooks/useParticipants.d.ts +62 -0
- package/build/hooks/useParticipants.d.ts.map +1 -0
- package/build/hooks/useParticipants.js +32 -0
- package/build/hooks/useParticipants.js.map +1 -0
- package/build/hooks/useReconnection.d.ts +5 -0
- package/build/hooks/useReconnection.d.ts.map +1 -0
- package/build/hooks/useReconnection.js +23 -0
- package/build/hooks/useReconnection.js.map +1 -0
- package/build/hooks/useScreencast.d.ts +38 -0
- package/build/hooks/useScreencast.d.ts.map +1 -0
- package/build/hooks/useScreencast.js +81 -0
- package/build/hooks/useScreencast.js.map +1 -0
- package/build/index.d.ts +24 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +14 -0
- package/build/index.js.map +1 -0
- package/build/protos/fishjam/peer_notifications.d.ts +63 -0
- package/build/protos/fishjam/peer_notifications.d.ts.map +1 -0
- package/build/protos/fishjam/peer_notifications.js +235 -0
- package/build/protos/fishjam/peer_notifications.js.map +1 -0
- package/build/stats/types.d.ts +55 -0
- package/build/stats/types.d.ts.map +1 -0
- package/build/stats/types.js +2 -0
- package/build/stats/types.js.map +1 -0
- package/build/stats/useRTCStatistics.d.ts +8 -0
- package/build/stats/useRTCStatistics.d.ts.map +1 -0
- package/build/stats/useRTCStatistics.js +78 -0
- package/build/stats/useRTCStatistics.js.map +1 -0
- package/build/types.d.ts +43 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/expo-module.config.json +17 -0
- package/ios/Events.swift +13 -0
- package/ios/RNFishjamClient.podspec +30 -0
- package/ios/RNFishjamClient.swift +836 -0
- package/ios/RNFishjamClientModule.swift +220 -0
- package/ios/Utils.swift +43 -0
- package/ios/VideoPreviewView.swift +64 -0
- package/ios/VideoPreviewViewModule.swift +21 -0
- package/ios/VideoRendererView.swift +84 -0
- package/ios/VideoRendererViewModule.swift +17 -0
- package/ios/swift-format-config.json +56 -0
- package/package.json +89 -0
- package/plugin/broadcastExtensionFiles/Info.plist +27 -0
- package/plugin/broadcastExtensionFiles/MembraneBroadcastSampleHandler.swift +50 -0
- package/plugin/broadcastExtensionFiles/MembraneScreenBroadcastExtension.entitlements +10 -0
- package/plugin/src/withMembrane.ts +310 -0
- package/plugin/tsconfig.json +9 -0
- package/scripts/lint.sh +18 -0
- package/scripts/lint_check.sh +14 -0
- package/src/RNFishjamClientModule.ts +73 -0
- package/src/__tests__/index.test.tsx +199 -0
- package/src/common/client.ts +33 -0
- package/src/common/eventEmitter.ts +21 -0
- package/src/common/metadata.ts +12 -0
- package/src/common/webRTC.ts +31 -0
- package/src/components/VideoPreviewView.tsx +33 -0
- package/src/components/VideoRendererView.tsx +31 -0
- package/src/hooks/useAudioSettings.ts +115 -0
- package/src/hooks/useBandwidthEstimation.ts +24 -0
- package/src/hooks/useCamera.ts +270 -0
- package/src/hooks/useMicrophone.ts +38 -0
- package/src/hooks/useParticipants.ts +118 -0
- package/src/hooks/useReconnection.ts +41 -0
- package/src/hooks/useScreencast.ts +146 -0
- package/src/index.tsx +63 -0
- package/src/protos/fishjam/peer_notifications.ts +299 -0
- package/src/stats/types.ts +56 -0
- package/src/stats/useRTCStatistics.ts +97 -0
- package/src/types.ts +49 -0
- package/tsconfig.json +9 -0
- package/typedoc.json +5 -0
|
@@ -0,0 +1,836 @@
|
|
|
1
|
+
import AVKit
|
|
2
|
+
import ExpoModulesCore
|
|
3
|
+
import FishjamCloudClient
|
|
4
|
+
import React
|
|
5
|
+
import ReplayKit
|
|
6
|
+
import WebRTC
|
|
7
|
+
|
|
8
|
+
class RNFishjamClient: FishjamClientListener {
|
|
9
|
+
static var fishjamClient: FishjamClient? = nil
|
|
10
|
+
|
|
11
|
+
var isMicrophoneOn = false
|
|
12
|
+
var isCameraOn = false
|
|
13
|
+
var isScreencastOn = false
|
|
14
|
+
var isConnected = false
|
|
15
|
+
|
|
16
|
+
var connectPromise: Promise? = nil
|
|
17
|
+
|
|
18
|
+
var videoSimulcastConfig: SimulcastConfig = SimulcastConfig()
|
|
19
|
+
var localUserMetadata: Metadata = .init()
|
|
20
|
+
|
|
21
|
+
var screencastSimulcastConfig: SimulcastConfig = SimulcastConfig()
|
|
22
|
+
var screencastMaxBandwidth: TrackBandwidthLimit = .BandwidthLimit(0)
|
|
23
|
+
|
|
24
|
+
var captureDeviceId: String? = nil
|
|
25
|
+
|
|
26
|
+
var audioSessionMode: AVAudioSession.Mode = AVAudioSession.Mode.videoChat
|
|
27
|
+
var errorMessage: String?
|
|
28
|
+
|
|
29
|
+
let sendEvent: (_ eventName: String, _ data: [String: Any]) -> Void
|
|
30
|
+
|
|
31
|
+
static var onTracksUpdateListeners: [OnTrackUpdateListener] = []
|
|
32
|
+
|
|
33
|
+
init(sendEvent: @escaping (_ eventName: String, _ data: [String: Any]) -> Void) {
|
|
34
|
+
self.sendEvent = sendEvent
|
|
35
|
+
NotificationCenter.default.addObserver(
|
|
36
|
+
self,
|
|
37
|
+
selector: #selector(onRouteChangeNotification),
|
|
38
|
+
name: AVAudioSession.routeChangeNotification,
|
|
39
|
+
object: nil
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private func getSimulcastConfigFromOptions(simulcastConfig: RNSimulcastConfig) throws -> SimulcastConfig {
|
|
44
|
+
var activeEncodings: [TrackEncoding] = []
|
|
45
|
+
|
|
46
|
+
for encoding in simulcastConfig.activeEncodings {
|
|
47
|
+
if let fishjamEncoding = try? TrackEncoding(encoding) {
|
|
48
|
+
activeEncodings.append(fishjamEncoding)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return SimulcastConfig(
|
|
53
|
+
enabled: simulcastConfig.enabled,
|
|
54
|
+
activeEncodings: activeEncodings
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private func getMaxBandwidthFromOptions(maxBandwidth: RNTrackBandwidthLimit) -> TrackBandwidthLimit {
|
|
59
|
+
if let maxBandwidth: Int = maxBandwidth.get() {
|
|
60
|
+
return .BandwidthLimit(maxBandwidth)
|
|
61
|
+
} else if let maxBandwidth: [String: Int] = maxBandwidth.get() {
|
|
62
|
+
return .SimulcastBandwidthLimit(maxBandwidth)
|
|
63
|
+
}
|
|
64
|
+
return .BandwidthLimit(0)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
func create() {
|
|
68
|
+
RNFishjamClient.fishjamClient = FishjamClient(listener: self)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
func getVideoParametersFromOptions(connectionOptions: CameraConfig) throws -> VideoParameters {
|
|
72
|
+
let videoQuality = connectionOptions.quality
|
|
73
|
+
let flipVideo = connectionOptions.flipVideo
|
|
74
|
+
let videoBandwidthLimit = getMaxBandwidthFromOptions(maxBandwidth: connectionOptions.maxBandwidth)
|
|
75
|
+
let simulcastConfig = try getSimulcastConfigFromOptions(simulcastConfig: connectionOptions.simulcastConfig)
|
|
76
|
+
|
|
77
|
+
let preset: VideoParameters = {
|
|
78
|
+
switch videoQuality {
|
|
79
|
+
case "QVGA169":
|
|
80
|
+
return VideoParameters.presetQVGA169
|
|
81
|
+
case "VGA169":
|
|
82
|
+
return VideoParameters.presetVGA169
|
|
83
|
+
case "VQHD169":
|
|
84
|
+
return VideoParameters.presetQHD169
|
|
85
|
+
case "HD169":
|
|
86
|
+
return VideoParameters.presetHD169
|
|
87
|
+
case "FHD169":
|
|
88
|
+
return VideoParameters.presetFHD169
|
|
89
|
+
case "QVGA43":
|
|
90
|
+
return VideoParameters.presetQVGA43
|
|
91
|
+
case "VGA43":
|
|
92
|
+
return VideoParameters.presetVGA43
|
|
93
|
+
case "VQHD43":
|
|
94
|
+
return VideoParameters.presetQHD43
|
|
95
|
+
case "HD43":
|
|
96
|
+
return VideoParameters.presetHD43
|
|
97
|
+
case "FHD43":
|
|
98
|
+
return VideoParameters.presetFHD43
|
|
99
|
+
default:
|
|
100
|
+
return VideoParameters.presetVGA169
|
|
101
|
+
}
|
|
102
|
+
}()
|
|
103
|
+
let videoParameters = VideoParameters(
|
|
104
|
+
dimensions: flipVideo ? preset.dimensions.flip() : preset.dimensions,
|
|
105
|
+
maxBandwidth: videoBandwidthLimit,
|
|
106
|
+
simulcastConfig: simulcastConfig
|
|
107
|
+
)
|
|
108
|
+
return videoParameters
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private func getLocalVideoTrack() -> LocalVideoTrack? {
|
|
112
|
+
return RNFishjamClient.fishjamClient?.getLocalEndpoint().tracks.first { $0.value is LocalVideoTrack }?.value
|
|
113
|
+
as? LocalVideoTrack
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private func getLocalAudioTrack() -> LocalAudioTrack? {
|
|
117
|
+
return RNFishjamClient.fishjamClient?.getLocalEndpoint().tracks.first { $0.value is LocalAudioTrack }?.value
|
|
118
|
+
as? LocalAudioTrack
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private func getLocalScreencastTrack() -> LocalScreencastTrack? {
|
|
122
|
+
return RNFishjamClient.fishjamClient?.getLocalEndpoint().tracks.first { $0.value is LocalScreencastTrack }?
|
|
123
|
+
.value as? LocalScreencastTrack
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private func ensureCreated() throws {
|
|
127
|
+
if RNFishjamClient.fishjamClient == nil {
|
|
128
|
+
throw Exception(
|
|
129
|
+
name: "E_NOT_CREATED",
|
|
130
|
+
description: "Client not created. Call create"
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private func ensureConnected() throws {
|
|
136
|
+
if !isConnected {
|
|
137
|
+
throw Exception(
|
|
138
|
+
name: "E_NOT_CONNECTED",
|
|
139
|
+
description:
|
|
140
|
+
"Client not connected to server yet. Make sure to call connect() first!")
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private func ensureVideoTrack() throws {
|
|
145
|
+
if getLocalVideoTrack() == nil {
|
|
146
|
+
throw Exception(
|
|
147
|
+
name: "E_NO_LOCAL_VIDEO_TRACK",
|
|
148
|
+
description: "No local video track. Make sure to call connect() first!")
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private func ensureAudioTrack() throws {
|
|
153
|
+
if getLocalAudioTrack() == nil {
|
|
154
|
+
throw Exception(
|
|
155
|
+
name: "E_NO_LOCAL_AUDIO_TRACK",
|
|
156
|
+
description: "No local audio track. Make sure to call connect() first!")
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private func ensureScreencastTrack() throws {
|
|
161
|
+
if getLocalScreencastTrack() == nil {
|
|
162
|
+
throw Exception(
|
|
163
|
+
name: "E_NO_LOCAL_SCREENCAST_TRACK",
|
|
164
|
+
description: "No local screencast track. Make sure to toggle screencast on first!")
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
func onAuthError(reason: FishjamCloudClient.AuthError) {
|
|
169
|
+
if let connectPromise = connectPromise {
|
|
170
|
+
connectPromise.reject("E_MEMBRANE_CONNECT", "Failed to connect: socket error")
|
|
171
|
+
}
|
|
172
|
+
connectPromise = nil
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
func onAuthSuccess() {
|
|
176
|
+
joinRoom()
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
func connect(url: String, peerToken: String, peerMetadata: [String: Any], config: ConnectConfig, promise: Promise) {
|
|
180
|
+
connectPromise = promise
|
|
181
|
+
localUserMetadata = peerMetadata.toMetadata()
|
|
182
|
+
|
|
183
|
+
let reconnectConfig = FishjamCloudClient.ReconnectConfig(
|
|
184
|
+
maxAttempts: config.reconnectConfig.maxAttempts, initialDelayMs: config.reconnectConfig.initialDelayMs,
|
|
185
|
+
delayMs: config.reconnectConfig.delayMs)
|
|
186
|
+
|
|
187
|
+
RNFishjamClient.fishjamClient?.connect(
|
|
188
|
+
config: FishjamCloudClient.ConnectConfig(
|
|
189
|
+
websocketUrl: url, token: peerToken, peerMetadata: .init(peerMetadata), reconnectConfig: reconnectConfig
|
|
190
|
+
))
|
|
191
|
+
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
func joinRoom() {
|
|
195
|
+
RNFishjamClient.fishjamClient?.join(peerMetadata: localUserMetadata)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
func leaveRoom() {
|
|
199
|
+
if isScreencastOn {
|
|
200
|
+
let screencastExtensionBundleId =
|
|
201
|
+
Bundle.main.infoDictionary?["ScreencastExtensionBundleId"] as? String
|
|
202
|
+
DispatchQueue.main.async {
|
|
203
|
+
RPSystemBroadcastPickerView.show(for: screencastExtensionBundleId)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
isMicrophoneOn = false
|
|
207
|
+
isCameraOn = false
|
|
208
|
+
isScreencastOn = false
|
|
209
|
+
isConnected = false
|
|
210
|
+
RNFishjamClient.fishjamClient?.leave()
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
func startCamera(config: CameraConfig) throws {
|
|
214
|
+
try ensureCreated()
|
|
215
|
+
let cameraTrack = try createCameraTrack(config: config)
|
|
216
|
+
setCameraTrackState(cameraTrack, enabled: config.cameraEnabled)
|
|
217
|
+
emitEndpoints()
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private func createCameraTrack(config: CameraConfig) throws -> LocalVideoTrack {
|
|
221
|
+
try ensureCreated()
|
|
222
|
+
let videoParameters = try getVideoParametersFromOptions(connectionOptions: config)
|
|
223
|
+
videoSimulcastConfig = try getSimulcastConfigFromOptions(simulcastConfig: config.simulcastConfig)
|
|
224
|
+
return RNFishjamClient.fishjamClient!.createVideoTrack(
|
|
225
|
+
videoParameters: videoParameters,
|
|
226
|
+
metadata: config.videoTrackMetadata.toMetadata(),
|
|
227
|
+
captureDeviceName: config.captureDeviceId
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private func setCameraTrackState(_ cameraTrack: LocalVideoTrack, enabled: Bool) {
|
|
232
|
+
cameraTrack.enabled = enabled
|
|
233
|
+
isCameraOn = enabled
|
|
234
|
+
let eventName = EmitableEvents.IsCameraOn
|
|
235
|
+
let isCameraEnabledMap = [eventName: enabled]
|
|
236
|
+
emitEvent(name: eventName, data: isCameraEnabledMap)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
func toggleCamera() throws {
|
|
240
|
+
try ensureVideoTrack()
|
|
241
|
+
setCameraTrackState(getLocalVideoTrack()!, enabled: !isCameraOn)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
func flipCamera() throws {
|
|
245
|
+
try ensureVideoTrack()
|
|
246
|
+
getLocalVideoTrack()?.flipCamera()
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
func switchCamera(captureDeviceId: String) throws {
|
|
250
|
+
try ensureVideoTrack()
|
|
251
|
+
getLocalVideoTrack()?.switchCamera(deviceId: captureDeviceId)
|
|
252
|
+
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
func toggleMicrophone() throws -> Bool {
|
|
256
|
+
if let audioTrack = getLocalAudioTrack() {
|
|
257
|
+
setMicrophoneTrackState(audioTrack, enabled: !isMicrophoneOn)
|
|
258
|
+
} else {
|
|
259
|
+
try startMicrophone()
|
|
260
|
+
}
|
|
261
|
+
return isMicrophoneOn
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
func startMicrophone() throws {
|
|
265
|
+
let microphoneTrack = RNFishjamClient.fishjamClient!.createAudioTrack(
|
|
266
|
+
metadata: Metadata())
|
|
267
|
+
setAudioSessionMode()
|
|
268
|
+
setMicrophoneTrackState(microphoneTrack, enabled: true)
|
|
269
|
+
emitEndpoints()
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
private func setMicrophoneTrackState(_ microphoneTrack: LocalAudioTrack, enabled: Bool) {
|
|
273
|
+
microphoneTrack.enabled = enabled
|
|
274
|
+
isMicrophoneOn = enabled
|
|
275
|
+
let eventName = EmitableEvents.IsMicrophoneOn
|
|
276
|
+
let isMicrophoneOnMap = [eventName: enabled]
|
|
277
|
+
print(isMicrophoneOnMap)
|
|
278
|
+
emitEvent(name: eventName, data: isMicrophoneOnMap)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
func setAudioSessionMode() {
|
|
282
|
+
guard let localAudioTrack = getLocalAudioTrack() else {
|
|
283
|
+
return
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
switch self.audioSessionMode {
|
|
287
|
+
case AVAudioSession.Mode.videoChat:
|
|
288
|
+
localAudioTrack.setVideoChatMode()
|
|
289
|
+
break
|
|
290
|
+
case AVAudioSession.Mode.voiceChat:
|
|
291
|
+
localAudioTrack.setVoiceChatMode()
|
|
292
|
+
break
|
|
293
|
+
default:
|
|
294
|
+
localAudioTrack.setVideoChatMode()
|
|
295
|
+
break
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
func toggleScreencast(screencastOptions: ScreencastOptions) throws {
|
|
300
|
+
try ensureCreated()
|
|
301
|
+
try ensureConnected()
|
|
302
|
+
guard let screencastExtensionBundleId = Bundle.main.infoDictionary?["ScreencastExtensionBundleId"] as? String
|
|
303
|
+
else {
|
|
304
|
+
throw Exception(
|
|
305
|
+
name: "E_NO_BUNDLE_ID_SET",
|
|
306
|
+
description:
|
|
307
|
+
"No screencast extension bundle id set. Please set ScreencastExtensionBundleId in Info.plist"
|
|
308
|
+
)
|
|
309
|
+
}
|
|
310
|
+
guard let appGroupName = Bundle.main.infoDictionary?["AppGroupName"] as? String
|
|
311
|
+
else {
|
|
312
|
+
throw Exception(
|
|
313
|
+
name: "E_NO_APP_GROUP_SET",
|
|
314
|
+
description: "No app group name set. Please set AppGroupName in Info.plist")
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
guard !isScreencastOn
|
|
318
|
+
else {
|
|
319
|
+
DispatchQueue.main.async {
|
|
320
|
+
RPSystemBroadcastPickerView.show(for: screencastExtensionBundleId)
|
|
321
|
+
}
|
|
322
|
+
return
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
let simulcastConfig = try getSimulcastConfigFromOptions(simulcastConfig: screencastOptions.simulcastConfig)
|
|
326
|
+
|
|
327
|
+
screencastSimulcastConfig = simulcastConfig
|
|
328
|
+
screencastMaxBandwidth = getMaxBandwidthFromOptions(
|
|
329
|
+
maxBandwidth: screencastOptions.maxBandwidth)
|
|
330
|
+
let screencastMetadata = screencastOptions.screencastMetadata.toMetadata()
|
|
331
|
+
let videoParameters = getScreencastVideoParameters(options: screencastOptions)
|
|
332
|
+
RNFishjamClient.fishjamClient!.createScreencastTrack(
|
|
333
|
+
appGroup: appGroupName,
|
|
334
|
+
videoParameters: videoParameters,
|
|
335
|
+
metadata: screencastMetadata,
|
|
336
|
+
onStart: { [weak self] screencastTrack in
|
|
337
|
+
guard let self = self else {
|
|
338
|
+
DispatchQueue.main.async {
|
|
339
|
+
RPSystemBroadcastPickerView.show(for: screencastExtensionBundleId)
|
|
340
|
+
}
|
|
341
|
+
return
|
|
342
|
+
}
|
|
343
|
+
do {
|
|
344
|
+
//not sure should it be here, or outside or where?
|
|
345
|
+
try setScreencastTrackState(screencastTrack, enabled: true)
|
|
346
|
+
} catch {
|
|
347
|
+
os_log(
|
|
348
|
+
"Error starting screencast: %{public}s", log: log, type: .error,
|
|
349
|
+
String(describing: error)
|
|
350
|
+
)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
},
|
|
354
|
+
onStop: { [weak self] screencastTrack in
|
|
355
|
+
guard let self = self else {
|
|
356
|
+
return
|
|
357
|
+
}
|
|
358
|
+
do {
|
|
359
|
+
//not sure should it be here, or outside or where?
|
|
360
|
+
try setScreencastTrackState(screencastTrack, enabled: false)
|
|
361
|
+
} catch {
|
|
362
|
+
os_log(
|
|
363
|
+
"Error stopping screencast: %{public}s", log: log, type: .error,
|
|
364
|
+
String(describing: error)
|
|
365
|
+
)
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
)
|
|
369
|
+
DispatchQueue.main.async {
|
|
370
|
+
RPSystemBroadcastPickerView.show(for: screencastExtensionBundleId)
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
private func setScreencastTrackState(_ screencastTrack: LocalScreencastTrack, enabled: Bool) throws {
|
|
375
|
+
//was not present before, test and maybe delete?
|
|
376
|
+
screencastTrack.enabled = enabled
|
|
377
|
+
isScreencastOn = enabled
|
|
378
|
+
let eventName = EmitableEvents.IsScreencastOn
|
|
379
|
+
let isScreencastEnabled = [eventName: enabled]
|
|
380
|
+
emitEvent(name: eventName, data: isScreencastEnabled)
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
//returns local endpoint and remote endpoints
|
|
384
|
+
static func getLocalAndRemoteEndpoints() -> [Endpoint] {
|
|
385
|
+
let localEndpoint = RNFishjamClient.fishjamClient!.getLocalEndpoint()
|
|
386
|
+
let remoteEndpoints = RNFishjamClient.fishjamClient!.getRemoteEndpoints()
|
|
387
|
+
return [localEndpoint] + remoteEndpoints
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
func getPeers() throws -> [[String: Any?]] {
|
|
391
|
+
let endpoints = RNFishjamClient.getLocalAndRemoteEndpoints()
|
|
392
|
+
return endpoints.compactMap { endpoint in
|
|
393
|
+
[
|
|
394
|
+
"id": endpoint.id,
|
|
395
|
+
"isLocal": endpoint.id == RNFishjamClient.fishjamClient!.getLocalEndpoint().id,
|
|
396
|
+
"type": endpoint.type,
|
|
397
|
+
"metadata": endpoint.metadata,
|
|
398
|
+
"tracks": endpoint.tracks.values.compactMap { track -> [String: Any?]? in
|
|
399
|
+
switch track {
|
|
400
|
+
case let track as RemoteVideoTrack:
|
|
401
|
+
return [
|
|
402
|
+
"id": track.id,
|
|
403
|
+
"type": "Video",
|
|
404
|
+
"metadata": track.metadata,
|
|
405
|
+
"encoding": track.encoding?.description,
|
|
406
|
+
"encodingReason": track.encodingReason?.rawValue,
|
|
407
|
+
]
|
|
408
|
+
|
|
409
|
+
case let track as RemoteAudioTrack:
|
|
410
|
+
return [
|
|
411
|
+
"id": track.id,
|
|
412
|
+
"type": "Audio",
|
|
413
|
+
"metadata": track.metadata,
|
|
414
|
+
"vadStatus": track.vadStatus.rawValue,
|
|
415
|
+
]
|
|
416
|
+
|
|
417
|
+
case let track as LocalVideoTrack:
|
|
418
|
+
return [
|
|
419
|
+
"id": track.id,
|
|
420
|
+
"type": "Video",
|
|
421
|
+
"metadata": track.metadata,
|
|
422
|
+
]
|
|
423
|
+
|
|
424
|
+
case let track as LocalScreencastTrack:
|
|
425
|
+
return [
|
|
426
|
+
"id": track.id,
|
|
427
|
+
"type": "Video",
|
|
428
|
+
"metadata": track.metadata,
|
|
429
|
+
]
|
|
430
|
+
|
|
431
|
+
case let track as LocalAudioTrack:
|
|
432
|
+
return [
|
|
433
|
+
"id": track.id,
|
|
434
|
+
"type": "Audio",
|
|
435
|
+
"metadata": track.metadata,
|
|
436
|
+
]
|
|
437
|
+
|
|
438
|
+
default:
|
|
439
|
+
return nil
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
]
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
func getCaptureDevices() -> [[String: Any]] {
|
|
447
|
+
let devices = LocalVideoTrack.getCaptureDevices()
|
|
448
|
+
return devices.map { device -> [String: Any] in
|
|
449
|
+
return [
|
|
450
|
+
"id": device.uniqueID,
|
|
451
|
+
"name": device.localizedName,
|
|
452
|
+
"isFrontFacing": device.position == .front,
|
|
453
|
+
"isBackFacing": device.position == .back,
|
|
454
|
+
]
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
func updatePeerMetadata(metadata: [String: Any]) throws {
|
|
459
|
+
try ensureConnected()
|
|
460
|
+
RNFishjamClient.fishjamClient?.updatePeerMetadata(metadata: metadata.toMetadata())
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
func updateTrackMetadata(trackId: String, metadata: [String: Any]) {
|
|
464
|
+
RNFishjamClient.fishjamClient?.updateTrackMetadata(trackId: trackId, metadata: metadata.toMetadata())
|
|
465
|
+
emitEndpoints()
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
func updateLocalVideoTrackMetadata(metadata: [String: Any]) throws {
|
|
469
|
+
try ensureVideoTrack()
|
|
470
|
+
if let track = getLocalVideoTrack() {
|
|
471
|
+
updateTrackMetadata(trackId: track.id, metadata: metadata)
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
func updateLocalAudioTrackMetadata(metadata: [String: Any]) throws {
|
|
476
|
+
try ensureAudioTrack()
|
|
477
|
+
if let track = getLocalAudioTrack() {
|
|
478
|
+
updateTrackMetadata(trackId: track.id, metadata: metadata)
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
func updateLocalScreencastTrackMetadata(metadata: [String: Any]) throws {
|
|
483
|
+
try ensureScreencastTrack()
|
|
484
|
+
if let track = getLocalScreencastTrack() {
|
|
485
|
+
updateTrackMetadata(trackId: track.id, metadata: metadata)
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
private func toggleTrackEncoding(encoding: String, trackId: String, simulcastConfig: SimulcastConfig) throws
|
|
490
|
+
-> SimulcastConfig
|
|
491
|
+
{
|
|
492
|
+
try ensureCreated()
|
|
493
|
+
let trackEncoding = try TrackEncoding(encoding)
|
|
494
|
+
let trackEncodingActive = simulcastConfig.activeEncodings.contains(trackEncoding)
|
|
495
|
+
var updatedEncodings = simulcastConfig.activeEncodings
|
|
496
|
+
|
|
497
|
+
if trackEncodingActive {
|
|
498
|
+
RNFishjamClient.fishjamClient?.disableTrackEncoding(trackId: trackId, encoding: trackEncoding)
|
|
499
|
+
updatedEncodings.removeAll(where: { encoding in trackEncoding == encoding })
|
|
500
|
+
} else {
|
|
501
|
+
RNFishjamClient.fishjamClient?.enableTrackEncoding(trackId: trackId, encoding: trackEncoding)
|
|
502
|
+
updatedEncodings += [trackEncoding]
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
return SimulcastConfig(enabled: true, activeEncodings: updatedEncodings)
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
func toggleScreencastTrackEncoding(encoding: String) throws -> [String: Any] {
|
|
509
|
+
try ensureScreencastTrack()
|
|
510
|
+
if let track = getLocalScreencastTrack() {
|
|
511
|
+
screencastSimulcastConfig = try toggleTrackEncoding(
|
|
512
|
+
encoding: encoding, trackId: track.id, simulcastConfig: screencastSimulcastConfig)
|
|
513
|
+
}
|
|
514
|
+
return getSimulcastConfigAsRNMap(screencastSimulcastConfig)
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
func setScreencastTrackBandwidth(bandwidth: Int) throws {
|
|
518
|
+
try ensureScreencastTrack()
|
|
519
|
+
if let track = getLocalScreencastTrack() {
|
|
520
|
+
RNFishjamClient.fishjamClient?.setTrackBandwidth(trackId: track.id, bandwidthLimit: bandwidth)
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
func setScreencastTrackEncodingBandwidth(encoding: String, bandwidth: Int) throws {
|
|
525
|
+
try ensureScreencastTrack()
|
|
526
|
+
if let track = getLocalScreencastTrack() {
|
|
527
|
+
RNFishjamClient.fishjamClient?.setEncodingBandwidth(
|
|
528
|
+
trackId: track.id, encoding: encoding, bandwidthLimit: bandwidth)
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
func setTargetTrackEncoding(trackId: String, encoding: String) throws {
|
|
533
|
+
try ensureConnected()
|
|
534
|
+
let trackEncoding = try TrackEncoding(encoding)
|
|
535
|
+
RNFishjamClient.fishjamClient?.setTargetTrackEncoding(trackId: trackId, encoding: trackEncoding)
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
func toggleVideoTrackEncoding(encoding: String) throws -> [String: Any] {
|
|
539
|
+
try ensureVideoTrack()
|
|
540
|
+
try ensureConnected()
|
|
541
|
+
|
|
542
|
+
let track = getLocalVideoTrack()!
|
|
543
|
+
videoSimulcastConfig = try toggleTrackEncoding(
|
|
544
|
+
encoding: encoding, trackId: track.id, simulcastConfig: videoSimulcastConfig)
|
|
545
|
+
|
|
546
|
+
let eventName = EmitableEvents.SimulcastConfigUpdate
|
|
547
|
+
let simulcastConfigAsRNMap = getSimulcastConfigAsRNMap(videoSimulcastConfig)
|
|
548
|
+
emitEvent(name: eventName, data: simulcastConfigAsRNMap)
|
|
549
|
+
|
|
550
|
+
return simulcastConfigAsRNMap
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
func setVideoTrackEncodingBandwidth(encoding: String, bandwidth: Int) throws {
|
|
554
|
+
try ensureVideoTrack()
|
|
555
|
+
let track = getLocalVideoTrack()!
|
|
556
|
+
RNFishjamClient.fishjamClient?.setEncodingBandwidth(
|
|
557
|
+
trackId: track.id, encoding: encoding, bandwidthLimit: bandwidth)
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
func setVideoTrackBandwidth(bandwidth: Int) throws {
|
|
561
|
+
try ensureVideoTrack()
|
|
562
|
+
let track = getLocalVideoTrack()!
|
|
563
|
+
RNFishjamClient.fishjamClient?.setTrackBandwidth(trackId: track.id, bandwidthLimit: bandwidth)
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
func changeWebRTCLoggingSeverity(severity: String) throws {
|
|
567
|
+
switch severity {
|
|
568
|
+
case "verbose":
|
|
569
|
+
RNFishjamClient.fishjamClient?.changeWebRTCLoggingSeverity(severity: .verbose)
|
|
570
|
+
case "info":
|
|
571
|
+
RNFishjamClient.fishjamClient?.changeWebRTCLoggingSeverity(severity: .info)
|
|
572
|
+
case "warning":
|
|
573
|
+
RNFishjamClient.fishjamClient?.changeWebRTCLoggingSeverity(severity: .warning)
|
|
574
|
+
case "error":
|
|
575
|
+
RNFishjamClient.fishjamClient?.changeWebRTCLoggingSeverity(severity: .error)
|
|
576
|
+
case "none":
|
|
577
|
+
RNFishjamClient.fishjamClient?.changeWebRTCLoggingSeverity(severity: .none)
|
|
578
|
+
default:
|
|
579
|
+
throw Exception(
|
|
580
|
+
name: "E_INVALID_SEVERITY_LEVEL",
|
|
581
|
+
description: "Severity with name=\(severity) not found")
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
private func rtcOutboundStatsToRNMap(obj: RTCOutboundStats) -> [String: Any] {
|
|
586
|
+
var innerMap: [String: Double] = [:]
|
|
587
|
+
|
|
588
|
+
innerMap["bandwidth"] = obj.qualityLimitationDurations?.bandwidth ?? 0.0
|
|
589
|
+
innerMap["cpu"] = obj.qualityLimitationDurations?.cpu ?? 0.0
|
|
590
|
+
innerMap["none"] = obj.qualityLimitationDurations?.none ?? 0.0
|
|
591
|
+
innerMap["other"] = obj.qualityLimitationDurations?.other ?? 0.0
|
|
592
|
+
|
|
593
|
+
var res: [String: Any] = [:]
|
|
594
|
+
res["kind"] = obj.kind
|
|
595
|
+
res["rid"] = obj.rid
|
|
596
|
+
res["bytesSent"] = obj.bytesSent
|
|
597
|
+
res["targetBitrate"] = obj.targetBitrate
|
|
598
|
+
res["packetsSent"] = obj.packetsSent
|
|
599
|
+
res["framesEncoded"] = obj.framesEncoded
|
|
600
|
+
res["framesPerSecond"] = obj.framesPerSecond
|
|
601
|
+
res["frameWidth"] = obj.frameWidth
|
|
602
|
+
res["frameHeight"] = obj.frameHeight
|
|
603
|
+
res["qualityLimitationDurations"] = innerMap
|
|
604
|
+
|
|
605
|
+
return res
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
private func rtcInboundStatsToRNMap(obj: RTCInboundStats) -> [String: Any] {
|
|
609
|
+
var res: [String: Any] = [:]
|
|
610
|
+
res["kind"] = obj.kind
|
|
611
|
+
res["jitter"] = obj.jitter
|
|
612
|
+
res["packetsLost"] = obj.packetsLost
|
|
613
|
+
res["packetsReceived"] = obj.packetsReceived
|
|
614
|
+
res["bytesReceived"] = obj.bytesReceived
|
|
615
|
+
res["framesReceived"] = obj.framesReceived
|
|
616
|
+
res["frameWidth"] = obj.frameWidth
|
|
617
|
+
res["frameHeight"] = obj.frameHeight
|
|
618
|
+
res["framesPerSecond"] = obj.framesPerSecond
|
|
619
|
+
res["framesDropped"] = obj.framesDropped
|
|
620
|
+
|
|
621
|
+
return res
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
func getStatistics() throws -> [String: Any] {
|
|
625
|
+
try ensureCreated()
|
|
626
|
+
|
|
627
|
+
let stats = RNFishjamClient.fishjamClient!.getStats()
|
|
628
|
+
let pairs = stats.map { (key, value) in
|
|
629
|
+
let rnValue =
|
|
630
|
+
value is RTCOutboundStats
|
|
631
|
+
? rtcOutboundStatsToRNMap(obj: value as! RTCOutboundStats)
|
|
632
|
+
: rtcInboundStatsToRNMap(obj: value as! RTCInboundStats)
|
|
633
|
+
return (key, rnValue)
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
return Dictionary(uniqueKeysWithValues: pairs)
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
private func getScreencastVideoParameters(options: ScreencastOptions) -> VideoParameters {
|
|
640
|
+
let preset: VideoParameters
|
|
641
|
+
switch options.quality {
|
|
642
|
+
case "VGA":
|
|
643
|
+
preset = VideoParameters.presetScreenShareVGA
|
|
644
|
+
case "HD5":
|
|
645
|
+
preset = VideoParameters.presetScreenShareHD5
|
|
646
|
+
case "HD15":
|
|
647
|
+
preset = VideoParameters.presetScreenShareHD15
|
|
648
|
+
case "FHD15":
|
|
649
|
+
preset = VideoParameters.presetScreenShareFHD15
|
|
650
|
+
case "FHD30":
|
|
651
|
+
preset = VideoParameters.presetScreenShareFHD30
|
|
652
|
+
default:
|
|
653
|
+
preset = VideoParameters.presetScreenShareHD15
|
|
654
|
+
}
|
|
655
|
+
return VideoParameters(
|
|
656
|
+
dimensions: preset.dimensions.flip(),
|
|
657
|
+
maxBandwidth: screencastMaxBandwidth,
|
|
658
|
+
maxFps: preset.maxFps,
|
|
659
|
+
simulcastConfig: screencastSimulcastConfig
|
|
660
|
+
)
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
func emitEvent(name: String, data: [String: Any]) {
|
|
664
|
+
sendEvent(name, data)
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
func emitEndpoints() {
|
|
668
|
+
let eventName = EmitableEvents.PeersUpdate
|
|
669
|
+
let EndpointsUpdateMap = [eventName: (try? getPeers()) ?? []]
|
|
670
|
+
emitEvent(name: eventName, data: EndpointsUpdateMap)
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
func onJoined(peerID: String, peersInRoom: [String: Endpoint]) {
|
|
674
|
+
isConnected = true
|
|
675
|
+
connectPromise?.resolve(nil)
|
|
676
|
+
connectPromise = nil
|
|
677
|
+
emitEndpoints()
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
func onJoinError(metadata: Any) {
|
|
681
|
+
connectPromise?.reject("E_MEMBRANE_CONNECT", "Failed to join room")
|
|
682
|
+
connectPromise = nil
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
private func addOrUpdateTrack(_ track: Track) {
|
|
686
|
+
if track is RemoteAudioTrack {
|
|
687
|
+
(track as! RemoteAudioTrack).setVadChangedListener { track in
|
|
688
|
+
self.emitEndpoints()
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
if track is RemoteVideoTrack {
|
|
693
|
+
(track as! RemoteVideoTrack).setOnEncodingChangedListener { track in
|
|
694
|
+
self.emitEndpoints()
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
RNFishjamClient.onTracksUpdateListeners.forEach {
|
|
699
|
+
$0.onTrackUpdate()
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
emitEndpoints()
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
func onTrackReady(track: Track) {
|
|
706
|
+
addOrUpdateTrack(track)
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
func onTrackAdded(track: Track) {}
|
|
710
|
+
|
|
711
|
+
func onTrackRemoved(track: Track) {
|
|
712
|
+
emitEndpoints()
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
func onTrackUpdated(track: Track) {
|
|
716
|
+
emitEndpoints()
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
func onPeerJoined(endpoint: Endpoint) {
|
|
720
|
+
emitEndpoints()
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
func onPeerLeft(endpoint: Endpoint) {
|
|
724
|
+
emitEndpoints()
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
func onPeerUpdated(endpoint: Endpoint) {}
|
|
728
|
+
|
|
729
|
+
func onSocketClose(code: UInt16, reason: String) {
|
|
730
|
+
if let connectPromise = connectPromise {
|
|
731
|
+
connectPromise.reject(
|
|
732
|
+
"E_MEMBRANE_CONNECT", "Failed to connect: socket close, code: \(code), reason: \(reason)")
|
|
733
|
+
}
|
|
734
|
+
connectPromise = nil
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
func onSocketError() {
|
|
738
|
+
if let connectPromise = connectPromise {
|
|
739
|
+
connectPromise.reject("E_MEMBRANE_CONNECT", "Failed to connect: socket error")
|
|
740
|
+
}
|
|
741
|
+
connectPromise = nil
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
func onSocketOpen() {}
|
|
745
|
+
|
|
746
|
+
func onDisconnected() {}
|
|
747
|
+
|
|
748
|
+
func getSimulcastConfigAsRNMap(_ simulcastConfig: SimulcastConfig) -> [String: Any] {
|
|
749
|
+
return [
|
|
750
|
+
"enabled": simulcastConfig.enabled,
|
|
751
|
+
"activeEncodings": simulcastConfig.activeEncodings.map { e in e.description },
|
|
752
|
+
]
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
func selectAudioSessionMode(sessionMode: String) throws {
|
|
756
|
+
switch sessionMode {
|
|
757
|
+
case "videoChat":
|
|
758
|
+
self.audioSessionMode = AVAudioSession.Mode.videoChat
|
|
759
|
+
break
|
|
760
|
+
case "voiceChat":
|
|
761
|
+
self.audioSessionMode = AVAudioSession.Mode.voiceChat
|
|
762
|
+
break
|
|
763
|
+
default:
|
|
764
|
+
throw Exception(
|
|
765
|
+
name: "E_MEMBRANE_AUDIO_SESSION",
|
|
766
|
+
description:
|
|
767
|
+
"Invalid audio session mode: \(sessionMode). Supported modes: videoChat, voiceChat"
|
|
768
|
+
)
|
|
769
|
+
}
|
|
770
|
+
setAudioSessionMode()
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
func showAudioRoutePicker() {
|
|
774
|
+
DispatchQueue.main.sync {
|
|
775
|
+
let pickerView = AVRoutePickerView()
|
|
776
|
+
if let button = pickerView.subviews.first(where: { $0 is UIButton }) as? UIButton {
|
|
777
|
+
button.sendActions(for: .touchUpInside)
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
func startAudioSwitcher() {
|
|
783
|
+
onRouteChangeNotification()
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
@objc func onRouteChangeNotification() {
|
|
787
|
+
let currentRoute = AVAudioSession.sharedInstance().currentRoute
|
|
788
|
+
let output = currentRoute.outputs[0]
|
|
789
|
+
let deviceType = output.portType
|
|
790
|
+
var deviceTypeString: String = ""
|
|
791
|
+
|
|
792
|
+
switch deviceType {
|
|
793
|
+
case .bluetoothA2DP, .bluetoothLE, .bluetoothHFP:
|
|
794
|
+
deviceTypeString = "bluetooth"
|
|
795
|
+
break
|
|
796
|
+
case .builtInSpeaker:
|
|
797
|
+
deviceTypeString = "speaker"
|
|
798
|
+
break
|
|
799
|
+
case .builtInReceiver:
|
|
800
|
+
deviceTypeString = "earpiece"
|
|
801
|
+
break
|
|
802
|
+
case .headphones:
|
|
803
|
+
deviceTypeString = "headphones"
|
|
804
|
+
break
|
|
805
|
+
default:
|
|
806
|
+
deviceTypeString = deviceType.rawValue
|
|
807
|
+
}
|
|
808
|
+
let eventName = EmitableEvents.AudioDeviceUpdate
|
|
809
|
+
emitEvent(
|
|
810
|
+
name: eventName,
|
|
811
|
+
data: [
|
|
812
|
+
eventName: [
|
|
813
|
+
"selectedDevice": ["name": output.portName, "type": deviceTypeString],
|
|
814
|
+
"availableDevices": [],
|
|
815
|
+
]
|
|
816
|
+
] as [String: [String: Any]])
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
func onBandwidthEstimationChanged(estimation: Int) {
|
|
820
|
+
let eventName = EmitableEvents.BandwidthEstimation
|
|
821
|
+
emitEvent(name: eventName, data: [eventName: estimation])
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
func onReconnectionStarted() {
|
|
825
|
+
emitEvent(name: EmitableEvents.ReconnectionStarted, data: [:])
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
func onReconnected() {
|
|
829
|
+
emitEvent(name: EmitableEvents.Reconnected, data: [:])
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
func onReconnectionRetriesLimitReached() {
|
|
833
|
+
emitEvent(name: EmitableEvents.ReconnectionRetriesLimitReached, data: [:])
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
}
|