edoctor-sendbird-calls 1.0.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/LICENSE +20 -0
- package/README.md +33 -0
- package/android/build.gradle +82 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +34 -0
- package/android/src/main/AndroidManifestNew.xml +2 -0
- package/android/src/main/java/com/edoctorsendbirdcalls/ComingCallActivity.java +41 -0
- package/android/src/main/java/com/edoctorsendbirdcalls/RNSendBirdCallsModule.java +2068 -0
- package/android/src/main/java/com/edoctorsendbirdcalls/RNSendBirdCallsPackage.java +32 -0
- package/android/src/main/java/com/edoctorsendbirdcalls/RNVSendBirdCallsVideo.java +10 -0
- package/android/src/main/java/com/edoctorsendbirdcalls/RNVSendBirdCallsVideoManager.java +77 -0
- package/android/src/main/java/com/edoctorsendbirdcalls/RNVideoViewGroup.java +109 -0
- package/android/src/main/java/com/edoctorsendbirdcalls/SharedUtils.java +127 -0
- package/android/src/main/java/com/edoctorsendbirdcalls/VcCallReceiver.java +37 -0
- package/android/src/main/java/com/edoctorsendbirdcalls/VcHeadlessService.java +23 -0
- package/android/src/main/java/com/edoctorsendbirdcalls/VoIPBaseService.java +100 -0
- package/android/src/main/java/com/edoctorsendbirdcalls/VoIPService.java +164 -0
- package/android/src/main/java/com/edoctorsendbirdcalls/XiaomiUtilities.java +75 -0
- package/android/src/main/res/drawable/bar_selector_white.xml +18 -0
- package/android/src/main/res/drawable/button_answer.xml +8 -0
- package/android/src/main/res/drawable/button_reject.xml +8 -0
- package/android/src/main/res/drawable/call_notification_line.xml +8 -0
- package/android/src/main/res/drawable/ic_answer.xml +5 -0
- package/android/src/main/res/drawable/ic_call_notification_answer.xml +6 -0
- package/android/src/main/res/drawable/ic_call_notification_decline.xml +9 -0
- package/android/src/main/res/drawable/ic_reject.xml +5 -0
- package/android/src/main/res/drawable/rn_edit_text_material.xml +36 -0
- package/android/src/main/res/layout/call_notification.xml +124 -0
- package/edoctor-sendbird-calls.podspec +27 -0
- package/ios/CXCallManager.swift +211 -0
- package/ios/CXProvider.swift +38 -0
- package/ios/Extensions/UIKit/UIColor.swift +30 -0
- package/ios/Extensions/UIKit/UIView+Extension.swift +61 -0
- package/ios/Extensions/UIKit/UIViewController.swift +28 -0
- package/ios/PrivacyInfo.xcprivacy +47 -0
- package/ios/RNSendBirdCalls-Bridging-Header.h +3 -0
- package/ios/RNSendBirdCalls.mm +94 -0
- package/ios/RNSendBirdCalls.swift +549 -0
- package/ios/RNSendBirdCallsHelper.swift +28 -0
- package/ios/RNVSendBirdCallsVideo.swift +55 -0
- package/ios/RNVSendBirdCallsVideoManager.mm +6 -0
- package/ios/RNVSendBirdCallsVideoManager.swift +15 -0
- package/ios/SendBirdCallsExtentions.swift +46 -0
- package/lib/module/SendBirdCalls.js +377 -0
- package/lib/module/SendBirdCalls.js.map +1 -0
- package/lib/module/SendBirdCallsEvents.js +108 -0
- package/lib/module/SendBirdCallsEvents.js.map +1 -0
- package/lib/module/SendBirdCallsVideo.js +33 -0
- package/lib/module/SendBirdCallsVideo.js.map +1 -0
- package/lib/module/index.js +14 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/index.type.js +2 -0
- package/lib/module/index.type.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/SendBirdCalls.d.ts +63 -0
- package/lib/typescript/src/SendBirdCalls.d.ts.map +1 -0
- package/lib/typescript/src/SendBirdCallsEvents.d.ts +36 -0
- package/lib/typescript/src/SendBirdCallsEvents.d.ts.map +1 -0
- package/lib/typescript/src/SendBirdCallsVideo.d.ts +18 -0
- package/lib/typescript/src/SendBirdCallsVideo.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +5 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/index.type.d.ts +14 -0
- package/lib/typescript/src/index.type.d.ts.map +1 -0
- package/package.json +154 -0
- package/src/SendBirdCalls.ts +472 -0
- package/src/SendBirdCallsEvents.ts +141 -0
- package/src/SendBirdCallsVideo.tsx +44 -0
- package/src/index.tsx +11 -0
- package/src/index.type.ts +20 -0
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import CallKit
|
|
3
|
+
import PushKit
|
|
4
|
+
import SendBirdCalls
|
|
5
|
+
import UIKit
|
|
6
|
+
import React
|
|
7
|
+
import AVFoundation
|
|
8
|
+
|
|
9
|
+
@objc(RNSendBirdCalls)
|
|
10
|
+
class RNSendBirdCalls: RCTEventEmitter, SendBirdCallDelegate, DirectCallDelegate, PKPushRegistryDelegate, SendBirdRecordingDelegate {
|
|
11
|
+
|
|
12
|
+
var queue: DispatchQueue = DispatchQueue(label: "RNSendBirdCalls")
|
|
13
|
+
var voipPushRegistry: PKPushRegistry?
|
|
14
|
+
var HAS_LISTENER = false
|
|
15
|
+
var CALL_ACTIVE: DirectCall?
|
|
16
|
+
|
|
17
|
+
let TAG = "[RNSendBirdCalls]_"
|
|
18
|
+
|
|
19
|
+
static let onEnded = "onEnded"
|
|
20
|
+
static let onRinging = "onRinging"
|
|
21
|
+
static let onConnected = "onConnected"
|
|
22
|
+
static let onReconnected = "onReconnected"
|
|
23
|
+
static let onReconnecting = "onReconnecting"
|
|
24
|
+
static let onCallDidAccept = "onCallDidAccept"
|
|
25
|
+
static let onRemoteAudioSettingsChanged = "onRemoteAudioSettingsChanged"
|
|
26
|
+
static let onRemoteVideoSettingsChanged = "onRemoteVideoSettingsChanged"
|
|
27
|
+
static let onRecordingSucceeded = "onRecordingSucceeded"
|
|
28
|
+
static let onRecordingFailed = "onRecordingFailed"
|
|
29
|
+
|
|
30
|
+
let jsEvents: NSMutableArray = []
|
|
31
|
+
|
|
32
|
+
override init() {
|
|
33
|
+
super.init()
|
|
34
|
+
setupSendBird()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
deinit {
|
|
38
|
+
removeAllEvents()
|
|
39
|
+
voipPushRegistry?.delegate = nil
|
|
40
|
+
voipPushRegistry = nil
|
|
41
|
+
CALL_ACTIVE?.delegate = nil
|
|
42
|
+
CALL_ACTIVE = nil
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private func setupSendBird() {
|
|
46
|
+
let userDefaults = UserDefaults(suiteName: "edoctorStorage")
|
|
47
|
+
let appId = "0BEF9C57-BA3B-474E-A40F-62B027AA47F6"
|
|
48
|
+
|
|
49
|
+
let config = SendBirdCall.configure(appId: appId)
|
|
50
|
+
if(config){
|
|
51
|
+
print(TAG + "CONFIG SUCCESS")
|
|
52
|
+
}else {
|
|
53
|
+
print(TAG + "CONFIG FAILED")
|
|
54
|
+
}
|
|
55
|
+
SendBirdCall.addDelegate(self, identifier: "RNSendBirdCalls")
|
|
56
|
+
SendBirdCall.setDirectCallDialingSoundOnWhenSilentMode(isEnabled: true)
|
|
57
|
+
SendBirdCall.addRecordingDelegate(self, identifier: "RNSendBirdRecording")
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// MARK: - RCTEventEmitter overrides for RN 0.79.x
|
|
61
|
+
override static func requiresMainQueueSetup() -> Bool {
|
|
62
|
+
return true
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
override func supportedEvents() -> [String]! {
|
|
66
|
+
return [
|
|
67
|
+
RNSendBirdCalls.onEnded,
|
|
68
|
+
RNSendBirdCalls.onRinging,
|
|
69
|
+
RNSendBirdCalls.onConnected,
|
|
70
|
+
RNSendBirdCalls.onReconnected,
|
|
71
|
+
RNSendBirdCalls.onReconnecting,
|
|
72
|
+
RNSendBirdCalls.onCallDidAccept,
|
|
73
|
+
RNSendBirdCalls.onRemoteAudioSettingsChanged,
|
|
74
|
+
RNSendBirdCalls.onRemoteVideoSettingsChanged,
|
|
75
|
+
RNSendBirdCalls.onRecordingSucceeded,
|
|
76
|
+
RNSendBirdCalls.onRecordingFailed,
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
override func startObserving() {
|
|
81
|
+
HAS_LISTENER = true
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
override func stopObserving() {
|
|
85
|
+
HAS_LISTENER = false
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@objc func setNativeEvent(_ event: String) {
|
|
89
|
+
DispatchQueue.main.async {
|
|
90
|
+
if !self.jsEvents.contains(event) {
|
|
91
|
+
self.jsEvents.add(event)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@objc func removeNativeEvent(_ event: String) {
|
|
97
|
+
DispatchQueue.main.async {
|
|
98
|
+
let index = self.jsEvents.index(of: event)
|
|
99
|
+
if index != NSNotFound {
|
|
100
|
+
self.jsEvents.removeObject(at: index)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@objc func removeAllEvents() {
|
|
106
|
+
DispatchQueue.main.async {
|
|
107
|
+
self.jsEvents.removeAllObjects()
|
|
108
|
+
}
|
|
109
|
+
SendBirdCall.removeAllDelegates()
|
|
110
|
+
SendBirdCall.removeAllRecordingDelegates()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// MARK: - SendBird Methods
|
|
114
|
+
@objc func shareStorage(
|
|
115
|
+
_ appId: String
|
|
116
|
+
) -> Void {
|
|
117
|
+
let userDefaults = UserDefaults(suiteName: "edoctorStorage")
|
|
118
|
+
userDefaults?.set(appId, forKey: "APP_ID_NATIVE")
|
|
119
|
+
userDefaults?.synchronize()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@objc func authenticate(_ userId: String, accessToken: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
|
|
123
|
+
let params = AuthenticateParams(userId: userId, accessToken: accessToken)
|
|
124
|
+
|
|
125
|
+
SendBirdCall.authenticate(with: params) { (user, error) in
|
|
126
|
+
guard let user = user, error == nil else {
|
|
127
|
+
let code = "\(error?.errorCode.rawValue ?? 0)"
|
|
128
|
+
let message = error?.localizedDescription ?? "Có lỗi xảy ra"
|
|
129
|
+
resolve(["succeeded": false , "errorCode": code, "errorMessage": message])
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
resolve(["succeeded": true ,"userId": user.userId, "nickname": user.nickname ?? ""])
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@objc func deAuthenticate(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) -> Void {
|
|
138
|
+
SendBirdCall.unregisterAllVoIPPushTokens { error in
|
|
139
|
+
guard error == nil else {
|
|
140
|
+
print("RNSendBirdCalls" + "Cerror deauthen")
|
|
141
|
+
let message = error?.localizedDescription ?? "Có lỗi xảy ra"
|
|
142
|
+
print("RNSendBirdCalls" + message)
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
SendBirdCall.deauthenticate { (error) in
|
|
147
|
+
guard error == nil else {
|
|
148
|
+
let code = "\(error?.errorCode.rawValue ?? 0)"
|
|
149
|
+
let message = error?.localizedDescription ?? "Có lỗi xảy ra"
|
|
150
|
+
resolve(["succeeded": false , "errorCode": code, "errorMessage": message])
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
resolve(["succeeded": true ])
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
@objc func initSendBird(_ appId: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
|
|
159
|
+
let config = SendBirdCall.configure(appId: appId)
|
|
160
|
+
if(config){
|
|
161
|
+
resolve(["succeeded": true ])
|
|
162
|
+
}else {
|
|
163
|
+
resolve(["succeeded": false ])
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
@objc func dial(_ calleeId: String, isVideoCall: Bool, isVideoEnable: Bool, isAudioEnable: Bool, appointmentScheduleId: String, eClinicId: String , resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock){
|
|
168
|
+
print(TAG + "DIAL")
|
|
169
|
+
let callOptions = CallOptions(isAudioEnabled: isAudioEnable, isVideoEnabled: isVideoEnable, useFrontCamera: true)
|
|
170
|
+
let customItems = [
|
|
171
|
+
"appointmentScheduleId": appointmentScheduleId,
|
|
172
|
+
"eClinicId": eClinicId
|
|
173
|
+
]
|
|
174
|
+
let params = DialParams(calleeId: calleeId, isVideoCall: isVideoCall, callOptions: callOptions, customItems: customItems)
|
|
175
|
+
|
|
176
|
+
let directCall = SendBirdCall.dial(with: params) { call, error in
|
|
177
|
+
guard let call = call, error == nil else {
|
|
178
|
+
let code = "\(error?.errorCode.rawValue ?? 0)"
|
|
179
|
+
let message = error?.localizedDescription ?? "Có lỗi xảy ra"
|
|
180
|
+
resolve(["succeeded": false , "errorCode": code, "errorMessage": message])
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
resolve(["succeeded": true ,"callId": call.callId, "caller": call.caller?.userId ?? "", "callee": call.callee?.userId ?? ""])
|
|
185
|
+
}
|
|
186
|
+
CALL_ACTIVE = directCall;
|
|
187
|
+
directCall?.delegate = self
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@objc func endCall(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
191
|
+
print(TAG + "END CALL")
|
|
192
|
+
guard let call = CALL_ACTIVE else {
|
|
193
|
+
resolve(["succeeded": false , "errorMessage": "Cuộc gọi không tồn tại"])
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
call.end()
|
|
197
|
+
CXCallManager.shared.endCXCall(call)
|
|
198
|
+
let params = getParamFromDirectCall(call: call)
|
|
199
|
+
params.setValue(true, forKey: "succeeded")
|
|
200
|
+
resolve(params)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
@objc func acceptCall(_ callId: String, isVideoEnable: Bool, isAudioEnable: Bool, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
204
|
+
print(TAG + "ACCEPT CALL")
|
|
205
|
+
guard let call = SendBirdCall.getCall(forCallId: callId) else {
|
|
206
|
+
resolve(["succeeded": false , "errorMessage": "Cuộc gọi không tồn tại"])
|
|
207
|
+
return
|
|
208
|
+
}
|
|
209
|
+
let callOptions = CallOptions(isAudioEnabled: isAudioEnable, isVideoEnabled: isVideoEnable, useFrontCamera: true)
|
|
210
|
+
let acceptParams = AcceptParams(callOptions: callOptions)
|
|
211
|
+
call.accept(with: acceptParams)
|
|
212
|
+
let params = getParamFromDirectCall(call: call)
|
|
213
|
+
params.setValue(true, forKey: "succeeded")
|
|
214
|
+
resolve(params)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
@objc func voipRegistry() {
|
|
218
|
+
self.voipPushRegistry = PKPushRegistry(queue: DispatchQueue.main)
|
|
219
|
+
self.voipPushRegistry?.delegate = self
|
|
220
|
+
self.voipPushRegistry?.desiredPushTypes = [.voIP]
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
@objc func addDirectCallSound(_ soundType: String, filename: String) {
|
|
224
|
+
if(soundType == "DIALING"){
|
|
225
|
+
SendBirdCall.addDirectCallSound(filename, forType: .dialing)
|
|
226
|
+
}else if(soundType == "RINGING"){
|
|
227
|
+
SendBirdCall.addDirectCallSound(filename, forType: .ringing)
|
|
228
|
+
}else if(soundType == "RECONNECTING"){
|
|
229
|
+
SendBirdCall.addDirectCallSound(filename, forType: .reconnecting)
|
|
230
|
+
}else if(soundType == "RECONNECTED"){
|
|
231
|
+
SendBirdCall.addDirectCallSound(filename, forType: .reconnected)
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
@objc func setDirectCallDialingSoundOnWhenSilentMode(_ isEnabled: Bool) {
|
|
236
|
+
SendBirdCall.setDirectCallDialingSoundOnWhenSilentMode(isEnabled: isEnabled)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
@objc func getOngoingCalls(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
240
|
+
let ongoingCalls = SendBirdCall.getOngoingCalls()
|
|
241
|
+
var resultData: [NSDictionary] = []
|
|
242
|
+
|
|
243
|
+
if(ongoingCalls.count > 0){
|
|
244
|
+
ongoingCalls.forEach({ directCall in
|
|
245
|
+
resultData.append(getParamFromDirectCall(call: directCall))
|
|
246
|
+
})
|
|
247
|
+
}
|
|
248
|
+
resolve(resultData)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
@objc func muteMicrophone(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
252
|
+
print(TAG + "muteMicrophone")
|
|
253
|
+
if(CALL_ACTIVE != nil){
|
|
254
|
+
CALL_ACTIVE?.muteMicrophone()
|
|
255
|
+
resolve(["succeeded": true])
|
|
256
|
+
}else {
|
|
257
|
+
resolve(["succeeded": false , "errorMessage": "Cuộc gọi không tồn tại"])
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
@objc func unmuteMicrophone(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
262
|
+
print(TAG + "unmuteMicrophone")
|
|
263
|
+
if(CALL_ACTIVE != nil){
|
|
264
|
+
CALL_ACTIVE?.unmuteMicrophone()
|
|
265
|
+
resolve(["succeeded": true])
|
|
266
|
+
}else {
|
|
267
|
+
resolve(["succeeded": false , "errorMessage": "Cuộc gọi không tồn tại"])
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
@objc func startVideo(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
272
|
+
print(TAG + "startVideo")
|
|
273
|
+
if(CALL_ACTIVE != nil){
|
|
274
|
+
CALL_ACTIVE?.startVideo()
|
|
275
|
+
resolve(["succeeded": true])
|
|
276
|
+
}else {
|
|
277
|
+
resolve(["succeeded": false , "errorMessage": "Cuộc gọi không tồn tại"])
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
@objc func stopVideo(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
282
|
+
print(TAG + "stopVideo")
|
|
283
|
+
if(CALL_ACTIVE != nil){
|
|
284
|
+
CALL_ACTIVE?.stopVideo()
|
|
285
|
+
resolve(["succeeded": true])
|
|
286
|
+
}else {
|
|
287
|
+
resolve(["succeeded": false , "errorMessage": "Cuộc gọi không tồn tại"])
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
@objc func switchCamera(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
292
|
+
print(TAG + "switchCamera")
|
|
293
|
+
if(CALL_ACTIVE != nil){
|
|
294
|
+
CALL_ACTIVE?.switchCamera { error in
|
|
295
|
+
if(error != nil){
|
|
296
|
+
let code = "\(error?.errorCode.rawValue ?? 0)"
|
|
297
|
+
let message = error?.localizedDescription ?? "Có lỗi xảy ra"
|
|
298
|
+
resolve(["succeeded": false , "errorCode": code, "errorMessage": message])
|
|
299
|
+
}else {
|
|
300
|
+
resolve(["succeeded": true])
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
} else {
|
|
304
|
+
resolve(["succeeded": false , "errorMessage": "Cuộc gọi không tồn tại"])
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
@objc func startRecording(_ fileName: String, isRemote: Bool, resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
309
|
+
print(TAG + "startRecording")
|
|
310
|
+
|
|
311
|
+
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
|
|
312
|
+
let documentsDirectory = paths[0]
|
|
313
|
+
|
|
314
|
+
let options = isRemote ? RecordingOptions(recordingType: .localAudioRemoteAudioAndVideo, directoryPath: documentsDirectory, fileName: fileName) : RecordingOptions(recordingType: .localAudioAndVideoRemoteAudio, directoryPath: documentsDirectory, fileName: fileName)
|
|
315
|
+
|
|
316
|
+
if(CALL_ACTIVE != nil){
|
|
317
|
+
CALL_ACTIVE?.startRecording(options: options) { (recordingId, error) in
|
|
318
|
+
if(error == nil){
|
|
319
|
+
let result: NSDictionary = [
|
|
320
|
+
"succeeded": true,
|
|
321
|
+
"recordingId": recordingId ?? "",
|
|
322
|
+
"filePath": documentsDirectory.description,
|
|
323
|
+
]
|
|
324
|
+
resolve(result)
|
|
325
|
+
}else {
|
|
326
|
+
let result: NSDictionary = [
|
|
327
|
+
"succeeded": false,
|
|
328
|
+
"recordingId": recordingId ?? "",
|
|
329
|
+
]
|
|
330
|
+
resolve(result)
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}else {
|
|
334
|
+
let result: NSDictionary = [
|
|
335
|
+
"succeeded": false,
|
|
336
|
+
]
|
|
337
|
+
resolve(result)
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
@objc func stopRecording(_ recordingId: String, isVideoCall: Bool, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock){
|
|
342
|
+
print(TAG + "stopRecording")
|
|
343
|
+
if(CALL_ACTIVE != nil){
|
|
344
|
+
let resultStop: Bool = ((CALL_ACTIVE?.stopRecording(recordingId: recordingId)) != nil)
|
|
345
|
+
let result: NSDictionary = [
|
|
346
|
+
"succeeded": resultStop,
|
|
347
|
+
]
|
|
348
|
+
resolve(result)
|
|
349
|
+
}else {
|
|
350
|
+
let result: NSDictionary = [
|
|
351
|
+
"succeeded": false,
|
|
352
|
+
]
|
|
353
|
+
resolve(result)
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
@objc func endAllCalls(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
358
|
+
let ongoingCalls = SendBirdCall.getOngoingCalls()
|
|
359
|
+
if(ongoingCalls.count > 0){
|
|
360
|
+
ongoingCalls.forEach({ directCall in
|
|
361
|
+
directCall.end()
|
|
362
|
+
CXCallManager.shared.endCXCall(directCall)
|
|
363
|
+
})
|
|
364
|
+
}
|
|
365
|
+
resolve(["succeeded": true])
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
func endCalls() {
|
|
369
|
+
let ongoingCalls = SendBirdCall.getOngoingCalls()
|
|
370
|
+
if(ongoingCalls.count > 0){
|
|
371
|
+
ongoingCalls.forEach({ directCall in
|
|
372
|
+
directCall.end()
|
|
373
|
+
CXCallManager.shared.endCXCall(directCall)
|
|
374
|
+
})
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// MARK: - PKPushRegistryDelegate
|
|
379
|
+
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
|
|
380
|
+
SendBirdCall.registerVoIPPush(token: pushCredentials.token, unique: true) { error in
|
|
381
|
+
guard error == nil else { return }
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) {
|
|
386
|
+
print(TAG + "pushRegistry incoming push event")
|
|
387
|
+
SendBirdCall.pushRegistry(registry, didReceiveIncomingPushWith: payload, for: type, completionHandler: nil)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
@available(iOS 10.0, *)
|
|
391
|
+
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
|
|
392
|
+
print(TAG + "pushRegistry pushRegistry incoming call")
|
|
393
|
+
SendBirdCall.addDelegate(self, identifier: "RNSendBirdCalls")
|
|
394
|
+
SendBirdCall.pushRegistry(registry, didReceiveIncomingPushWith: payload, for: type) { uuid in
|
|
395
|
+
guard uuid != nil else {
|
|
396
|
+
let update = CXCallUpdate()
|
|
397
|
+
update.remoteHandle = CXHandle(type: .generic, value: "invalid")
|
|
398
|
+
let randomUUID = UUID()
|
|
399
|
+
|
|
400
|
+
CXCallManager.shared.reportIncomingCall(with: randomUUID, update: update) { _ in
|
|
401
|
+
CXCallManager.shared.endCall(for: randomUUID, endedAt: Date(), reason: .acceptFailed)
|
|
402
|
+
}
|
|
403
|
+
completion()
|
|
404
|
+
return
|
|
405
|
+
}
|
|
406
|
+
completion()
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// MARK: - Helper Methods
|
|
411
|
+
func getParamFromDirectCall(call: DirectCall) -> NSMutableDictionary {
|
|
412
|
+
let calleeMap: NSDictionary = [
|
|
413
|
+
"userId": call.callee?.userId ?? "",
|
|
414
|
+
"nickname": call.callee?.nickname ?? "",
|
|
415
|
+
"profileURL": call.callee?.profileURL ?? "",
|
|
416
|
+
]
|
|
417
|
+
|
|
418
|
+
let callerMap: NSDictionary = [
|
|
419
|
+
"userId": call.caller?.userId ?? "",
|
|
420
|
+
"nickname": call.caller?.nickname ?? "",
|
|
421
|
+
"profileURL": call.caller?.profileURL ?? "",
|
|
422
|
+
]
|
|
423
|
+
|
|
424
|
+
let callId = call.callId
|
|
425
|
+
let isVideoCall = call.isVideoCall
|
|
426
|
+
let duration: Int64 = call.duration
|
|
427
|
+
let isRemoteAudioEnabled = call.isRemoteAudioEnabled
|
|
428
|
+
let isRemoteVideoEnabled = call.isRemoteVideoEnabled
|
|
429
|
+
let isLocalVideoEnabled = call.isLocalVideoEnabled
|
|
430
|
+
let isLocalAudioEnabled = call.isLocalAudioEnabled
|
|
431
|
+
let customItems = call.customItems
|
|
432
|
+
|
|
433
|
+
let params: NSMutableDictionary = [
|
|
434
|
+
"callId" : callId ?? "",
|
|
435
|
+
"duration": duration,
|
|
436
|
+
"isRemoteAudioEnabled": isRemoteAudioEnabled,
|
|
437
|
+
"isRemoteVideoEnabled": isRemoteVideoEnabled,
|
|
438
|
+
"isLocalVideoEnabled": isLocalVideoEnabled,
|
|
439
|
+
"isLocalAudioEnabled": isLocalAudioEnabled,
|
|
440
|
+
"isVideoCall": isVideoCall,
|
|
441
|
+
"callee" : calleeMap,
|
|
442
|
+
"caller" : callerMap,
|
|
443
|
+
"customItems": customItems ?? [:],
|
|
444
|
+
]
|
|
445
|
+
return params
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
func sendEventWithName(eventName: String, params: NSDictionary) {
|
|
449
|
+
// Ensure we're on main queue for RN 0.79.x
|
|
450
|
+
DispatchQueue.main.async {
|
|
451
|
+
if self.jsEvents.contains(eventName) && self.HAS_LISTENER && self.bridge != nil {
|
|
452
|
+
self.sendEvent(withName: eventName, body: params)
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// MARK: - SendBirdCallDelegate
|
|
458
|
+
func didStartRinging(_ directCall: DirectCall) {
|
|
459
|
+
print(TAG + "onRinging")
|
|
460
|
+
directCall.delegate = self
|
|
461
|
+
CALL_ACTIVE = directCall
|
|
462
|
+
|
|
463
|
+
guard let uuid = directCall.callUUID else { return }
|
|
464
|
+
guard CXCallManager.shared.shouldProcessCall(for: uuid) else { return }
|
|
465
|
+
|
|
466
|
+
let name = "BS. \(directCall.caller?.nickname ?? "Chưa xác định")"
|
|
467
|
+
let update = CXCallUpdate()
|
|
468
|
+
update.remoteHandle = CXHandle(type: .generic, value: name)
|
|
469
|
+
update.hasVideo = directCall.isVideoCall
|
|
470
|
+
update.localizedCallerName = "BS. \(directCall.caller?.nickname ?? "Chưa xác định")"
|
|
471
|
+
|
|
472
|
+
if SendBirdCall.getOngoingCallCount() > 1 {
|
|
473
|
+
CXCallManager.shared.reportIncomingCall(with: uuid, update: update) { _ in
|
|
474
|
+
CXCallManager.shared.endCall(for: uuid, endedAt: Date(), reason: .declined)
|
|
475
|
+
}
|
|
476
|
+
directCall.end()
|
|
477
|
+
} else {
|
|
478
|
+
CXCallManager.shared.reportIncomingCall(with: uuid, update: update)
|
|
479
|
+
let params = getParamFromDirectCall(call: directCall)
|
|
480
|
+
sendEventWithName(eventName: RNSendBirdCalls.onRinging, params: params)
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
func didEstablish(_ directCall: DirectCall) {
|
|
485
|
+
print(TAG + "onCallDidAccept")
|
|
486
|
+
let params = getParamFromDirectCall(call: directCall)
|
|
487
|
+
sendEventWithName(eventName: RNSendBirdCalls.onCallDidAccept, params: params)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
func didConnect(_ directCall: DirectCall) {
|
|
491
|
+
print(TAG + "onConnected")
|
|
492
|
+
let params = getParamFromDirectCall(call: directCall)
|
|
493
|
+
sendEventWithName(eventName: RNSendBirdCalls.onConnected, params: params)
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
func didStartReconnecting(_ directCall: DirectCall) {
|
|
497
|
+
print(TAG + "onReconnecting")
|
|
498
|
+
let params = getParamFromDirectCall(call: directCall)
|
|
499
|
+
sendEventWithName(eventName: RNSendBirdCalls.onReconnecting, params: params)
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
func didReconnect(_ directCall: DirectCall) {
|
|
503
|
+
print(TAG + "didReconnect")
|
|
504
|
+
let params = getParamFromDirectCall(call: directCall)
|
|
505
|
+
sendEventWithName(eventName: RNSendBirdCalls.onReconnected, params: params)
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
func didRemoteAudioSettingsChange(_ directCall: DirectCall) {
|
|
509
|
+
print(TAG + "onRemoteAudioSettingsChanged")
|
|
510
|
+
let params = getParamFromDirectCall(call: directCall)
|
|
511
|
+
sendEventWithName(eventName: RNSendBirdCalls.onRemoteAudioSettingsChanged, params: params)
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
func didRemoteVideoSettingsChange(_ directCall: DirectCall) {
|
|
515
|
+
print(TAG + "onRemoteVideoSettingsChanged")
|
|
516
|
+
let params = getParamFromDirectCall(call: directCall)
|
|
517
|
+
sendEventWithName(eventName: RNSendBirdCalls.onRemoteVideoSettingsChanged, params: params)
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
func didEnd(_ directCall: DirectCall) {
|
|
521
|
+
var callId: UUID = UUID()
|
|
522
|
+
if let callUUID = directCall.callUUID {
|
|
523
|
+
callId = callUUID
|
|
524
|
+
}
|
|
525
|
+
print(TAG + "didEnd")
|
|
526
|
+
CALL_ACTIVE = nil
|
|
527
|
+
let params = getParamFromDirectCall(call: directCall)
|
|
528
|
+
sendEventWithName(eventName: RNSendBirdCalls.onEnded, params: params)
|
|
529
|
+
CXCallManager.shared.endCall(for: callId, endedAt: Date(), reason: directCall.endResult)
|
|
530
|
+
guard let callLog = directCall.callLog else { return }
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// MARK: - SendBirdRecordingDelegate
|
|
534
|
+
func didSaveRecording(call: DirectCall, recordingId: String, options: RecordingOptions, outputURL: URL) {
|
|
535
|
+
print(TAG + "didSaveRecording")
|
|
536
|
+
let recordingMap: NSDictionary = [
|
|
537
|
+
"outputFilePath": outputURL.absoluteString,
|
|
538
|
+
]
|
|
539
|
+
sendEventWithName(eventName: RNSendBirdCalls.onRecordingSucceeded, params: recordingMap)
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
func didFailToSaveRecording(call: DirectCall, recordingId: String, error: SBCError) {
|
|
543
|
+
print(TAG + "didFailToSaveRecording")
|
|
544
|
+
let recordingMap: NSDictionary = [
|
|
545
|
+
"errorMessage": error.localizedDescription,
|
|
546
|
+
]
|
|
547
|
+
sendEventWithName(eventName: RNSendBirdCalls.onRecordingFailed, params: recordingMap)
|
|
548
|
+
}
|
|
549
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import SendBirdCalls
|
|
2
|
+
@objc(RNSendBirdCallsHelper)
|
|
3
|
+
public class RNSendBirdCallsHelper: NSObject {
|
|
4
|
+
@objc public static func applicationWillTerminate(application: UIApplication?) -> Void {
|
|
5
|
+
print("sayHello2")
|
|
6
|
+
|
|
7
|
+
// This method will be called when the app is forcefully terminated.
|
|
8
|
+
// End all ongoing calls in this method.
|
|
9
|
+
let callManager = CXCallManager.shared
|
|
10
|
+
let ongoingCalls = callManager.currentCalls.compactMap { SendBirdCall.getCall(forUUID: $0.uuid) }
|
|
11
|
+
|
|
12
|
+
ongoingCalls.forEach { directCall in
|
|
13
|
+
// Sendbird Calls: End call
|
|
14
|
+
directCall.end()
|
|
15
|
+
|
|
16
|
+
// CallKit: Request End transaction
|
|
17
|
+
callManager.endCXCall(directCall)
|
|
18
|
+
|
|
19
|
+
// CallKit: Report End if uuid is valid
|
|
20
|
+
if let uuid = directCall.callUUID {
|
|
21
|
+
callManager.endCall(for: uuid, endedAt: Date(), reason: .none)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// However, because iOS gives a limited time to perform remaining tasks,
|
|
25
|
+
// There might be some calls failed to be ended
|
|
26
|
+
// In this case, I recommend that you register local notification to notify the unterminated calls.
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import SendBirdCalls
|
|
2
|
+
import CoreGraphics
|
|
3
|
+
|
|
4
|
+
@objc(RNVSendBirdCallsVideo)
|
|
5
|
+
class RNVSendBirdCallsVideo : UIView {
|
|
6
|
+
@objc var callId: String = ""
|
|
7
|
+
@objc var local: Bool = true
|
|
8
|
+
@objc var scaleFit: Bool = true
|
|
9
|
+
var videoView: SendBirdVideoView!
|
|
10
|
+
|
|
11
|
+
override init(frame: CGRect) {
|
|
12
|
+
super.init(frame: frame);
|
|
13
|
+
videoView = SendBirdVideoView(frame: self.frame)
|
|
14
|
+
videoView.backgroundColor = UIColor.gray
|
|
15
|
+
videoView.frame = self.bounds
|
|
16
|
+
self.addSubview(videoView)
|
|
17
|
+
}
|
|
18
|
+
required init?(coder aDecoder: NSCoder) {
|
|
19
|
+
fatalError("init(coder:) has not been implemented")
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
override func layoutSubviews() {
|
|
23
|
+
videoView.frame = self.bounds
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
override func didSetProps(_ changedProps: [String]!) {
|
|
27
|
+
guard let call = SendBirdCall.getCall(forCallId: self.callId) else {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (self.scaleFit) {
|
|
32
|
+
self.videoView.videoContentMode = UIView.ContentMode.scaleAspectFit
|
|
33
|
+
} else {
|
|
34
|
+
self.videoView.videoContentMode = UIView.ContentMode.scaleAspectFill
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if self.local {
|
|
38
|
+
call.updateLocalVideoView(self.videoView)
|
|
39
|
+
}else{
|
|
40
|
+
call.updateRemoteVideoView(self.videoView)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
func setCallId(callId: String) {
|
|
45
|
+
self.callId = callId
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
func setScaleFit(scaleFit: Bool) {
|
|
49
|
+
self.scaleFit = scaleFit
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
func setLocal(local: Bool) {
|
|
53
|
+
self.local = local
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import SendBirdCalls
|
|
2
|
+
|
|
3
|
+
@objc(RNVSendBirdCallsVideoManager)
|
|
4
|
+
class RNVSendBirdCallsVideoManager: RCTViewManager {
|
|
5
|
+
|
|
6
|
+
override static func requiresMainQueueSetup() -> Bool{
|
|
7
|
+
return true
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
override func view() -> UIView! {
|
|
11
|
+
return RNVSendBirdCallsVideo()
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|