提交
This commit is contained in:
368
TUIKit/TUICallKit/TUICallKit-Swift/TUICallKitImpl.swift
Normal file
368
TUIKit/TUICallKit/TUICallKit-Swift/TUICallKitImpl.swift
Normal file
@@ -0,0 +1,368 @@
|
||||
//
|
||||
// TUICallKitImpl.swift
|
||||
// TUICallKit
|
||||
//
|
||||
// Created by vincepzhang on 2023/1/4.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import TUICore
|
||||
import UIKit
|
||||
import TUICallEngine
|
||||
|
||||
#if canImport(TXLiteAVSDK_TRTC)
|
||||
import TXLiteAVSDK_TRTC
|
||||
#elseif canImport(TXLiteAVSDK_Professional)
|
||||
import TXLiteAVSDK_Professional
|
||||
#endif
|
||||
|
||||
class TUICallKitImpl: TUICallKit {
|
||||
static let instance = TUICallKitImpl()
|
||||
let selfUserCallStatusObserver = Observer()
|
||||
let callingVibratorFeature = CallingVibratorFeature()
|
||||
let callingBellFeature = CallingBellFeature()
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
registerNotifications()
|
||||
registerObserveState()
|
||||
}
|
||||
|
||||
deinit {
|
||||
CallEngineManager.instance.removeObserver(TUICallState.instance)
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
TUICallState.instance.selfUser.value.callStatus.removeObserver(selfUserCallStatusObserver)
|
||||
}
|
||||
|
||||
// MARK: Implementation of external interface for TUICallKit
|
||||
override func setSelfInfo(nickname: String, avatar: String, succ: @escaping TUICallSucc, fail: @escaping TUICallFail) {
|
||||
CallEngineManager.instance.setSelfInfo(nickname: nickname, avatar: avatar) {
|
||||
succ()
|
||||
} fail: { code, message in
|
||||
fail(code,message)
|
||||
}
|
||||
}
|
||||
|
||||
override func call(userId: String, callMediaType: TUICallMediaType) {
|
||||
call(userId: userId, callMediaType: callMediaType, params: getCallParams()) {
|
||||
|
||||
} fail: { errCode, errMessage in
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override func call(userId: String, callMediaType: TUICallMediaType, params: TUICallParams,
|
||||
succ: @escaping TUICallSucc, fail: @escaping TUICallFail) {
|
||||
if TUILogin.getUserID() == nil {
|
||||
fail(ERROR_INIT_FAIL, "call failed, please login")
|
||||
return
|
||||
}
|
||||
|
||||
if userId.count <= 0 || userId == TUILogin.getUserID() {
|
||||
fail(ERROR_PARAM_INVALID, "call failed, invalid params 'userId'")
|
||||
return
|
||||
}
|
||||
|
||||
if WindowManager.instance.isFloating {
|
||||
fail(ERROR_PARAM_INVALID, "call failed, Unable to restart the call")
|
||||
TUITool.makeToast(TUICallKitLocalize(key: "TUICallKit.UnableToRestartTheCall"))
|
||||
return
|
||||
}
|
||||
|
||||
if callMediaType == .unknown {
|
||||
fail(ERROR_PARAM_INVALID, "call failed, callMediaType is Unknown")
|
||||
return
|
||||
}
|
||||
|
||||
if TUICallKitCommon.checkAuthorizationStatusIsDenied(mediaType: callMediaType) {
|
||||
showAuthorizationAlert(mediaType: callMediaType)
|
||||
fail(ERROR_PARAM_INVALID, "call failed, authorization status is denied")
|
||||
return
|
||||
}
|
||||
|
||||
CallEngineManager.instance.call(userId: userId, callMediaType: callMediaType, params: params) {
|
||||
succ()
|
||||
} fail: { [weak self] code, message in
|
||||
guard let self = self else { return }
|
||||
self.handleAbilityFailErrorMessage(code: code, message: message)
|
||||
fail(code, message)
|
||||
}
|
||||
}
|
||||
|
||||
override func groupCall(groupId: String, userIdList: [String], callMediaType: TUICallMediaType) {
|
||||
groupCall(groupId: groupId, userIdList: userIdList, callMediaType: callMediaType, params: getCallParams()) {
|
||||
|
||||
} fail: { code, message in
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override func groupCall(groupId: String, userIdList: [String], callMediaType: TUICallMediaType, params: TUICallParams,
|
||||
succ: @escaping TUICallSucc, fail: @escaping TUICallFail) {
|
||||
if TUILogin.getUserID() == nil {
|
||||
fail(ERROR_INIT_FAIL, "call failed, please login")
|
||||
return
|
||||
}
|
||||
|
||||
let userIdList = userIdList.filter { $0 != TUILogin.getUserID() }
|
||||
|
||||
if userIdList.isEmpty {
|
||||
fail(ERROR_PARAM_INVALID, "call failed, invalid params 'userIdList'")
|
||||
return
|
||||
}
|
||||
|
||||
if userIdList.count >= MAX_USER {
|
||||
fail(ERROR_PARAM_INVALID, "groupCall failed, currently supports call with up to 9 people")
|
||||
TUITool.makeToast(TUICallKitLocalize(key: "TUICallKit.User.Exceed.Limit"))
|
||||
return
|
||||
}
|
||||
|
||||
if WindowManager.instance.isFloating {
|
||||
fail(ERROR_PARAM_INVALID, "call failed, Unable to restart the call")
|
||||
TUITool.makeToast(TUICallKitLocalize(key: "TUICallKit.UnableToRestartTheCall"))
|
||||
return
|
||||
}
|
||||
|
||||
if callMediaType == .unknown {
|
||||
fail(ERROR_PARAM_INVALID, "call failed, callMediaType is Unknown")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if TUICallKitCommon.checkAuthorizationStatusIsDenied(mediaType: callMediaType) {
|
||||
showAuthorizationAlert(mediaType: callMediaType)
|
||||
fail(ERROR_PARAM_INVALID, "call failed, authorization status is denied")
|
||||
return
|
||||
}
|
||||
|
||||
CallEngineManager.instance.groupCall(groupId: groupId, userIdList: userIdList, callMediaType: callMediaType, params: params) {
|
||||
succ()
|
||||
} fail: { [weak self] code, message in
|
||||
guard let self = self else { return }
|
||||
self.handleAbilityFailErrorMessage(code: code, message: message)
|
||||
fail(code,message)
|
||||
}
|
||||
}
|
||||
|
||||
override func joinInGroupCall(roomId: TUIRoomId, groupId: String, callMediaType: TUICallMediaType) {
|
||||
if TUICallKitCommon.checkAuthorizationStatusIsDenied(mediaType: callMediaType) {
|
||||
showAuthorizationAlert(mediaType: callMediaType)
|
||||
return
|
||||
}
|
||||
|
||||
CallEngineManager.instance.joinInGroupCall(roomId: roomId, groupId: groupId, callMediaType: callMediaType) {
|
||||
|
||||
} fail: { [weak self] code, message in
|
||||
guard let self = self else { return }
|
||||
self.handleAbilityFailErrorMessage(code: code, message: message)
|
||||
}
|
||||
}
|
||||
|
||||
override func setCallingBell(filePath: String) {
|
||||
if filePath.hasPrefix("http") {
|
||||
let session = URLSession.shared
|
||||
guard let url = URL(string: filePath) else { return }
|
||||
let downloadTask = session.downloadTask(with: url) { location, response, error in
|
||||
if error != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if location != nil {
|
||||
if let oldBellFilePath = UserDefaults.standard.object(forKey: TUI_CALLING_BELL_KEY) as? String {
|
||||
do {
|
||||
try FileManager.default.removeItem(atPath: oldBellFilePath)
|
||||
} catch let error {
|
||||
debugPrint("FileManager Error: \(error)")
|
||||
}
|
||||
}
|
||||
guard let location = location else { return }
|
||||
guard let dstDocPath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).last else { return }
|
||||
let dstPath = dstDocPath + "/" + location.lastPathComponent
|
||||
do {
|
||||
try FileManager.default.moveItem(at: location, to: URL(fileURLWithPath: dstPath))
|
||||
} catch let error {
|
||||
debugPrint("FileManager Error: \(error)")
|
||||
}
|
||||
UserDefaults.standard.set(dstPath, forKey: TUI_CALLING_BELL_KEY)
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
}
|
||||
downloadTask.resume()
|
||||
} else {
|
||||
UserDefaults.standard.set(filePath, forKey: TUI_CALLING_BELL_KEY)
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
}
|
||||
|
||||
override func enableMuteMode(enable: Bool) {
|
||||
UserDefaults.standard.set(enable, forKey: ENABLE_MUTEMODE_USERDEFAULT)
|
||||
TUICallState.instance.enableMuteMode = enable
|
||||
}
|
||||
|
||||
override func enableFloatWindow(enable: Bool) {
|
||||
TUICallState.instance.enableFloatWindow = enable
|
||||
}
|
||||
|
||||
override func enableCustomViewRoute(enable: Bool) {
|
||||
|
||||
}
|
||||
|
||||
override func getCallViewController() -> UIViewController {
|
||||
if let callWindowVC = WindowManager.instance.callWindow.rootViewController {
|
||||
return callWindowVC
|
||||
}
|
||||
|
||||
if let floatingWindowVC = WindowManager.instance.floatWindow.rootViewController {
|
||||
return floatingWindowVC
|
||||
}
|
||||
|
||||
return UIViewController()
|
||||
}
|
||||
|
||||
override func enableVirtualBackground (enable: Bool) {
|
||||
CallEngineManager.instance.reportOnlineLog(enable)
|
||||
TUICallState.instance.showVirtualBackgroundButton = enable
|
||||
}
|
||||
|
||||
override func enableIncomingBanner (enable: Bool) {
|
||||
TUICallState.instance.enableIncomingBanner = enable
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: Internal interface for TUICallKit
|
||||
private extension TUICallKitImpl {
|
||||
func registerNotifications() {
|
||||
NotificationCenter.default.addObserver(self,
|
||||
selector: #selector(loginSuccessNotification),
|
||||
name: NSNotification.Name.TUILoginSuccess,
|
||||
object: nil)
|
||||
NotificationCenter.default.addObserver(self,
|
||||
selector: #selector(logoutSuccessNotification),
|
||||
name: NSNotification.Name.TUILogoutSuccess,
|
||||
object: nil)
|
||||
NotificationCenter.default.addObserver(self,
|
||||
selector: #selector(showViewControllerNotification),
|
||||
name: NSNotification.Name(Constants.EVENT_SHOW_TUICALLKIT_VIEWCONTROLLER),
|
||||
object: nil)
|
||||
}
|
||||
|
||||
@objc func loginSuccessNotification(noti: Notification) {
|
||||
initEngine()
|
||||
initState()
|
||||
CallEngineManager.instance.addObserver(TUICallState.instance)
|
||||
CallEngineManager.instance.setFramework()
|
||||
CallEngineManager.instance.setExcludeFromHistoryMessage()
|
||||
}
|
||||
|
||||
@objc func logoutSuccessNotification(noti: Notification) {
|
||||
CallEngineManager.instance.hangup()
|
||||
TUICallEngine.destroyInstance()
|
||||
TUICallState.instance.cleanState()
|
||||
}
|
||||
|
||||
@objc func showViewControllerNotification(noti: Notification) {
|
||||
CallEngineManager.instance.setAudioPlaybackDevice(device: TUICallState.instance.audioDevice.value)
|
||||
WindowManager.instance.showCallWindow(false)
|
||||
}
|
||||
|
||||
func initEngine() {
|
||||
CallEngineManager.instance.initEngine(sdkAppId:TUILogin.getSdkAppID(),
|
||||
userId: TUILogin.getUserID() ?? "",
|
||||
userSig: TUILogin.getUserSig() ?? "") {} fail: { Int32errCode, errMessage in }
|
||||
|
||||
let videoEncoderParams = TUIVideoEncoderParams()
|
||||
videoEncoderParams.resolution = ._640_360
|
||||
videoEncoderParams.resolutionMode = .portrait
|
||||
CallEngineManager.instance.setVideoEncoderParams(params: videoEncoderParams) {} fail: { Int32errCode, errMessage in }
|
||||
|
||||
let videoRenderParams = TUIVideoRenderParams()
|
||||
videoRenderParams.fillMode = .fill
|
||||
videoRenderParams.rotation = ._0
|
||||
CallEngineManager.instance.setVideoRenderParams(userId: TUILogin.getUserID() ?? "",
|
||||
params: videoRenderParams) {} fail: { Int32errCode, errMessage in }
|
||||
|
||||
let beauty = CallEngineManager.instance.getTRTCCloudInstance().getBeautyManager()
|
||||
beauty.setBeautyStyle(.nature)
|
||||
beauty.setBeautyLevel(6.0)
|
||||
}
|
||||
|
||||
func initState() {
|
||||
CallEngineManager.instance.addObserver(TUICallState.instance)
|
||||
User.getSelfUserInfo(response: { selfUser in
|
||||
TUICallState.instance.selfUser.value.id.value = selfUser.id.value
|
||||
TUICallState.instance.selfUser.value.nickname.value = selfUser.nickname.value
|
||||
TUICallState.instance.selfUser.value.avatar.value = selfUser.avatar.value
|
||||
})
|
||||
}
|
||||
|
||||
func registerObserveState() {
|
||||
TUICallState.instance.selfUser.value.callStatus.addObserver(selfUserCallStatusObserver, closure: { newValue, _ in
|
||||
if TUICallState.instance.selfUser.value.callRole.value != TUICallRole.none {
|
||||
if TUICallState.instance.selfUser.value.callStatus.value == TUICallStatus.waiting {
|
||||
TUICallState.instance.audioDevice.value = TUIAudioPlaybackDevice.earpiece
|
||||
CallEngineManager.instance.setAudioPlaybackDevice(device: TUIAudioPlaybackDevice.earpiece)
|
||||
WindowManager.instance.showCallWindow(TUICallState.instance.enableIncomingBanner)
|
||||
} else if TUICallState.instance.selfUser.value.callStatus.value == TUICallStatus.accept && !WindowManager.instance.isFloating {
|
||||
WindowManager.instance.showCallWindow(false)
|
||||
}
|
||||
} else {
|
||||
if TUICallState.instance.selfUser.value.callStatus.value == TUICallStatus.none {
|
||||
WindowManager.instance.closeCallWindow()
|
||||
WindowManager.instance.closeFloatWindow()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func showAuthorizationAlert(mediaType: TUICallMediaType) {
|
||||
let statusVideo: AVAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: .video)
|
||||
var deniedType: AuthorizationDeniedType = AuthorizationDeniedType.audio
|
||||
|
||||
if mediaType == .video && statusVideo == .denied {
|
||||
deniedType = .video
|
||||
}
|
||||
|
||||
TUICallKitCommon.showAuthorizationAlert(deniedType: deniedType) {
|
||||
CallEngineManager.instance.hangup()
|
||||
} cancelHandler: {
|
||||
CallEngineManager.instance.hangup()
|
||||
}
|
||||
}
|
||||
|
||||
func getCallParams() -> TUICallParams {
|
||||
let offlinePushInfo = OfflinePushInfoConfig.createOfflinePushInfo()
|
||||
let callParams = TUICallParams()
|
||||
callParams.offlinePushInfo = offlinePushInfo
|
||||
callParams.timeout = TUI_CALLKIT_SIGNALING_MAX_TIME
|
||||
return callParams
|
||||
}
|
||||
|
||||
func convertCallKitError(code: Int32, message: String?) -> String {
|
||||
var errorMessage: String? = message
|
||||
if code == ERROR_PACKAGE_NOT_PURCHASED {
|
||||
errorMessage = TUICallKitLocalize(key: "TUICallKit.purchased")
|
||||
} else if code == ERROR_PACKAGE_NOT_SUPPORTED {
|
||||
errorMessage = TUICallKitLocalize(key: "TUICallKit.support")
|
||||
} else if code == ERR_SVR_MSG_IN_PEER_BLACKLIST.rawValue {
|
||||
errorMessage = TUICallKitLocalize(key: "TUICallKit.ErrorInPeerBlacklist")
|
||||
} else if code == ERROR_INIT_FAIL {
|
||||
errorMessage = TUICallKitLocalize(key: "TUICallKit.ErrorInvalidLogin")
|
||||
} else if code == ERROR_PARAM_INVALID {
|
||||
errorMessage = TUICallKitLocalize(key: "TUICallKit.ErrorParameterInvalid")
|
||||
} else if code == ERROR_REQUEST_REFUSED {
|
||||
errorMessage = TUICallKitLocalize(key: "TUICallKit.ErrorRequestRefused")
|
||||
} else if code == ERROR_REQUEST_REPEATED {
|
||||
errorMessage = TUICallKitLocalize(key: "TUICallKit.ErrorRequestRepeated")
|
||||
} else if code == ERROR_SCENE_NOT_SUPPORTED {
|
||||
errorMessage = TUICallKitLocalize(key: "TUICallKit.ErrorSceneNotSupport")
|
||||
}
|
||||
return errorMessage ?? ""
|
||||
}
|
||||
|
||||
func handleAbilityFailErrorMessage(code: Int32, message: String?) {
|
||||
let errorMessage = TUITool.convertIMError(Int(code), msg: convertCallKitError(code: code, message: message))
|
||||
TUITool.makeToast(errorMessage ?? "", duration: 4)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user